From cd74b83c213b03028c7a5da79c1b315ab03aeec4 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 7 Apr 2020 14:03:58 -0600 Subject: [PATCH] Make most python tests pass with Python 3.4 Dictionary order is not stable in Python < 3.6 so we need to sort by key to have consistent results. The LogHandler output is also different on older Python versions. Also, don't stop running python tests after the first error. --- plugins/python/pyhelpers.c | 29 +++++++++++++- plugins/python/python_plugin_common.c | 4 +- .../python/regress/check_python_examples.c | 5 ++- plugins/python/regress/iohelpers.c | 2 +- .../python/regress/plugin_approval_test.py | 2 +- .../check_example_debugging_c_calls@diag.log | 6 +-- .../check_example_debugging_c_calls@info.log | 6 +-- .../check_example_debugging_py_calls@diag.log | 2 +- .../check_example_debugging_py_calls@info.log | 2 +- ...mple_policy_plugin_validate_invalidate.log | 2 +- ...check_loading_fails_wrong_classname.stderr | 2 +- ...tiple_approval_plugin_and_arguments.stdout | 40 +++++++++---------- plugins/python/regress/testhelpers.h | 14 +++---- 13 files changed, 72 insertions(+), 44 deletions(-) diff --git a/plugins/python/pyhelpers.c b/plugins/python/pyhelpers.c index d2d2629b0..d43c7348b 100644 --- a/plugins/python/pyhelpers.c +++ b/plugins/python/pyhelpers.c @@ -312,10 +312,35 @@ _py_debug_python_function(const char *class_name, const char *function_name, con if (sudo_debug_needed(SUDO_DEBUG_DIAG)) { char *args_str = NULL; char *kwargs_str = NULL; - if (py_args != NULL) + if (py_args != NULL) { + /* Sort by key for consistent output on Python < 3.6 */ + PyObject *py_args_sorted = NULL; + if (PyDict_Check(py_args)) { + py_args_sorted = PyDict_Items(py_args); + if (py_args_sorted != NULL) { + if (PyList_Sort(py_args_sorted) == 0) { + py_args = py_args_sorted; + } + } + } args_str = py_create_string_rep(py_args); + if (py_args_sorted != NULL) + Py_DECREF(py_args_sorted); + } if (py_kwargs != NULL) { + /* Sort by key for consistent output on Python < 3.6 */ + PyObject *py_kwargs_sorted = NULL; + if (PyDict_Check(py_kwargs)) { + py_kwargs_sorted = PyDict_Items(py_kwargs); + if (py_kwargs_sorted != NULL) { + if (PyList_Sort(py_kwargs_sorted) == 0) { + py_kwargs = py_kwargs_sorted; + } + } + } kwargs_str = py_create_string_rep(py_kwargs); + if (py_kwargs_sorted != NULL) + Py_DECREF(py_kwargs_sorted); } if (args_str == NULL) @@ -334,7 +359,7 @@ void py_debug_python_call(const char *class_name, const char *function_name, PyObject *py_args, PyObject *py_kwargs, int subsystem_id) { - debug_decl_vars(_py_debug_python_function, subsystem_id); + debug_decl_vars(py_debug_python_call, subsystem_id); if (subsystem_id == PYTHON_DEBUG_C_CALLS && sudo_debug_needed(SUDO_DEBUG_INFO)) { // at this level we also output the callee python script diff --git a/plugins/python/python_plugin_common.c b/plugins/python/python_plugin_common.c index 689c04784..1ef36e779 100644 --- a/plugins/python/python_plugin_common.c +++ b/plugins/python/python_plugin_common.c @@ -62,7 +62,7 @@ CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION int _append_python_path(const char *module_dir) { - debug_decl(_py_debug_python_function, PYTHON_DEBUG_PLUGIN_LOAD); + debug_decl(_append_python_path, PYTHON_DEBUG_PLUGIN_LOAD); int rc = -1; PyObject *py_sys_path = PySys_GetObject("path"); if (py_sys_path == NULL) { @@ -717,7 +717,7 @@ python_plugin_unlink(void) return; if (Py_IsInitialized()) { - sudo_debug_printf(SUDO_DEBUG_NOTICE, "Closing: deinit python %lu subinterpreters\n", + sudo_debug_printf(SUDO_DEBUG_NOTICE, "Closing: deinit python %zu subinterpreters\n", py_ctx.interpreter_count); for (size_t i = 0; i < py_ctx.interpreter_count; ++i) { PyThreadState *py_interpreter = py_ctx.py_subinterpreters[i]; diff --git a/plugins/python/regress/check_python_examples.c b/plugins/python/regress/check_python_examples.c index ca1e60016..1f3266004 100644 --- a/plugins/python/regress/check_python_examples.c +++ b/plugins/python/regress/check_python_examples.c @@ -1511,6 +1511,8 @@ _unlink_symbols(void) int main(int argc, char *argv[]) { + int errors = 0; + if (argc != 2) { printf("Please specify the python_plugin.so as argument!\n"); return EXIT_FAILURE; @@ -1546,6 +1548,7 @@ main(int argc, char *argv[]) RUN_TEST(check_example_policy_plugin_version_display(true)); RUN_TEST(check_example_policy_plugin_version_display(false)); + // FIXME - sudo.options_from_dict fails for these two on python 3.4 RUN_TEST(check_example_policy_plugin_accepted_execution()); RUN_TEST(check_example_policy_plugin_failed_execution()); RUN_TEST(check_example_policy_plugin_denied_execution()); @@ -1593,5 +1596,5 @@ main(int argc, char *argv[]) RUN_TEST(check_example_debugging("plugin@err")); RUN_TEST(check_plugin_unload()); - return EXIT_SUCCESS; + return errors; } diff --git a/plugins/python/regress/iohelpers.c b/plugins/python/regress/iohelpers.c index 9303beb9d..9c71dfce2 100644 --- a/plugins/python/regress/iohelpers.c +++ b/plugins/python/regress/iohelpers.c @@ -82,7 +82,7 @@ freadall(const char *file_path, char *output, size_t max_len) } if (!feof(file)) { - printf("File '%s' was bigger than allocated buffer %lu", file_path, max_len); + printf("File '%s' was bigger than allocated buffer %zu", file_path, max_len); goto cleanup; } diff --git a/plugins/python/regress/plugin_approval_test.py b/plugins/python/regress/plugin_approval_test.py index ec602e388..69ea66820 100644 --- a/plugins/python/regress/plugin_approval_test.py +++ b/plugins/python/regress/plugin_approval_test.py @@ -8,7 +8,7 @@ class ApprovalTestPlugin(sudo.Plugin): super().__init__(plugin_options=plugin_options, **kwargs) self._id = "(APPROVAL {})".format(id) sudo.log_info("{} Constructed:".format(self._id)) - sudo.log_info(json.dumps(self.__dict__, indent=4)) + sudo.log_info(json.dumps(self.__dict__, indent=4, sort_keys=True)) def __del__(self): sudo.log_info("{} Destructed successfully".format(self._id)) diff --git a/plugins/python/regress/testdata/check_example_debugging_c_calls@diag.log b/plugins/python/regress/testdata/check_example_debugging_c_calls@diag.log index e3dce817b..5d5028459 100644 --- a/plugins/python/regress/testdata/check_example_debugging_c_calls@diag.log +++ b/plugins/python/regress/testdata/check_example_debugging_c_calls@diag.log @@ -1,6 +1,6 @@ sudo.debug was called with arguments: (, 'My demo purpose plugin shows this ERROR level debug message') sudo.debug was called with arguments: (, 'My demo purpose plugin shows this INFO level debug message') -LogHandler.emit was called with arguments: ( (NOTSET)>, ) -LogHandler.emit was called with arguments: ( (NOTSET)>, ) +LogHandler.emit was called with arguments: (<.*sudo.LogHandler.* +LogHandler.emit was called with arguments: (<.*sudo.LogHandler.* sudo.options_as_dict was called with arguments: (('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin'),) -sudo.options_as_dict returned result: {'ModulePath': 'SRC_DIR/example_debugging.py', 'ClassName': 'DebugDemoPlugin'} +sudo.options_as_dict returned result: \[('ClassName', 'DebugDemoPlugin'), ('ModulePath', 'SRC_DIR/example_debugging.py')\] diff --git a/plugins/python/regress/testdata/check_example_debugging_c_calls@info.log b/plugins/python/regress/testdata/check_example_debugging_c_calls@info.log index d08ff3ad5..fddfd973d 100644 --- a/plugins/python/regress/testdata/check_example_debugging_c_calls@info.log +++ b/plugins/python/regress/testdata/check_example_debugging_c_calls@info.log @@ -3,9 +3,9 @@ sudo.debug was called with arguments: (, 'My demo purpose plugin __init__ @ SRC_DIR/example_debugging.py:63 calls C function: sudo.debug was called with arguments: (, 'My demo purpose plugin shows this INFO level debug message') handle @ .*/logging/__init__.py:[0-9]* calls C function: -LogHandler.emit was called with arguments: ( (NOTSET)>, ) +LogHandler.emit was called with arguments: (<.*sudo.LogHandler.* handle @ .*/logging/__init__.py:[0-9]* calls C function: -LogHandler.emit was called with arguments: ( (NOTSET)>, ) +LogHandler.emit was called with arguments: (<.*sudo.LogHandler.* __init__ @ SRC_DIR/example_debugging.py:85 calls C function: sudo.options_as_dict was called with arguments: (('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin'),) -sudo.options_as_dict returned result: {'ModulePath': 'SRC_DIR/example_debugging.py', 'ClassName': 'DebugDemoPlugin'} +sudo.options_as_dict returned result: \[('ClassName', 'DebugDemoPlugin'), ('ModulePath', 'SRC_DIR/example_debugging.py')\] diff --git a/plugins/python/regress/testdata/check_example_debugging_py_calls@diag.log b/plugins/python/regress/testdata/check_example_debugging_py_calls@diag.log index 8c40f67c3..e56ec2f3a 100644 --- a/plugins/python/regress/testdata/check_example_debugging_py_calls@diag.log +++ b/plugins/python/regress/testdata/check_example_debugging_py_calls@diag.log @@ -1,2 +1,2 @@ -DebugDemoPlugin.__init__ was called with arguments: () {'version': '1.0', 'settings': ('debug_flags=/tmp/sudo_check_python_exampleXXXXXX/debug.log py_calls@diag', 'plugin_path=python_plugin.so'), 'user_env': (), 'user_info': (), 'plugin_options': ('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin')} +DebugDemoPlugin.__init__ was called with arguments: () \[('plugin_options', ('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin')), ('settings', ('debug_flags=/tmp/sudo_check_python_exampleXXXXXX/debug.log py_calls@diag', 'plugin_path=python_plugin.so')), ('user_env', ()), ('user_info', ()), ('version', '1.0')\] DebugDemoPlugin.__init__ returned result: diff --git a/plugins/python/regress/testdata/check_example_debugging_py_calls@info.log b/plugins/python/regress/testdata/check_example_debugging_py_calls@info.log index a67f146ff..829c809b9 100644 --- a/plugins/python/regress/testdata/check_example_debugging_py_calls@info.log +++ b/plugins/python/regress/testdata/check_example_debugging_py_calls@info.log @@ -1,4 +1,4 @@ -DebugDemoPlugin.__init__ was called with arguments: () {'version': '1.0', 'settings': ('debug_flags=/tmp/sudo_check_python_exampleXXXXXX/debug.log py_calls@info', 'plugin_path=python_plugin.so'), 'user_env': (), 'user_info': (), 'plugin_options': ('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin')} +DebugDemoPlugin.__init__ was called with arguments: () \[('plugin_options', ('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin')), ('settings', ('debug_flags=/tmp/sudo_check_python_exampleXXXXXX/debug.log py_calls@info', 'plugin_path=python_plugin.so')), ('user_env', ()), ('user_info', ()), ('version', '1.0')\] DebugDemoPlugin.__init__ returned result: DebugDemoPlugin function 'log_ttyin' is not implemented DebugDemoPlugin function 'log_ttyout' is not implemented diff --git a/plugins/python/regress/testdata/check_example_policy_plugin_validate_invalidate.log b/plugins/python/regress/testdata/check_example_policy_plugin_validate_invalidate.log index a6f684492..45a34360b 100644 --- a/plugins/python/regress/testdata/check_example_policy_plugin_validate_invalidate.log +++ b/plugins/python/regress/testdata/check_example_policy_plugin_validate_invalidate.log @@ -1,4 +1,4 @@ -SudoPolicyPlugin.__init__ was called with arguments: () {'version': '1.0', 'settings': (), 'user_env': (), 'user_info': (), 'plugin_options': ('ModulePath=SRC_DIR/example_policy_plugin.py', 'ClassName=SudoPolicyPlugin')} +SudoPolicyPlugin.__init__ was called with arguments: () \[('plugin_options', ('ModulePath=SRC_DIR/example_policy_plugin.py', 'ClassName=SudoPolicyPlugin')), ('settings', ()), ('user_env', ()), ('user_info', ()), ('version', '1.0')\] SudoPolicyPlugin.__init__ returned result: SudoPolicyPlugin.validate was called with arguments: () SudoPolicyPlugin.validate returned result: None diff --git a/plugins/python/regress/testdata/check_loading_fails_wrong_classname.stderr b/plugins/python/regress/testdata/check_loading_fails_wrong_classname.stderr index bf246e3b4..4477029ba 100644 --- a/plugins/python/regress/testdata/check_loading_fails_wrong_classname.stderr +++ b/plugins/python/regress/testdata/check_loading_fails_wrong_classname.stderr @@ -1,2 +1,2 @@ Failed to find plugin class 'MispelledPluginName' -Failed during loading plugin class: (AttributeError) module 'example_debugging' has no attribute 'MispelledPluginName' +Failed during loading plugin class: (AttributeError) .* has no attribute 'MispelledPluginName' diff --git a/plugins/python/regress/testdata/check_multiple_approval_plugin_and_arguments.stdout b/plugins/python/regress/testdata/check_multiple_approval_plugin_and_arguments.stdout index 64fc6b260..aae182d78 100644 --- a/plugins/python/regress/testdata/check_multiple_approval_plugin_and_arguments.stdout +++ b/plugins/python/regress/testdata/check_multiple_approval_plugin_and_arguments.stdout @@ -1,15 +1,23 @@ (APPROVAL 1) Constructed: { + "_id": "(APPROVAL 1)", "plugin_options": \[ "ModulePath=SRC_DIR/regress/plugin_approval_test.py", "ClassName=ApprovalTestPlugin", "Id=1" \], - "version": "1.15", "settings": \[ "SETTING1=VALUE1", "setting2=value2" \], + "submit_argv": \[ + "sudo", + "-u", + "user", + "whoami", + "--help" + \], + "submit_optind": 3, "user_env": \[ "USER_ENV1=VALUE1", "USER_ENV2=value2" @@ -18,28 +26,28 @@ "INFO1=VALUE1", "info2=value2" \], - "submit_optind": 3, - "submit_argv": \[ - "sudo", - "-u", - "user", - "whoami", - "--help" - \], - "_id": "(APPROVAL 1)" + "version": "1.15" } (APPROVAL 2) Constructed: { + "_id": "(APPROVAL 2)", "plugin_options": \[ "ModulePath=SRC_DIR/regress/plugin_approval_test.py", "ClassName=ApprovalTestPlugin", "Id=2" \], - "version": "1.15", "settings": \[ "SETTING1=VALUE1", "setting2=value2" \], + "submit_argv": \[ + "sudo", + "-u", + "user", + "whoami", + "--help" + \], + "submit_optind": 3, "user_env": \[ "USER_ENV1=VALUE1", "USER_ENV2=value2" @@ -48,15 +56,7 @@ "INFO1=VALUE1", "info2=value2" \], - "submit_optind": 3, - "submit_argv": \[ - "sudo", - "-u", - "user", - "whoami", - "--help" - \], - "_id": "(APPROVAL 2)" + "version": "1.15" } (APPROVAL 1) Show version was called with arguments: (0,) Python approval plugin (API 1.0): ApprovalTestPlugin (loaded from 'SRC_DIR/regress/plugin_approval_test.py') diff --git a/plugins/python/regress/testhelpers.h b/plugins/python/regress/testhelpers.h index b354280de..5bd65c10b 100644 --- a/plugins/python/regress/testhelpers.h +++ b/plugins/python/regress/testhelpers.h @@ -61,22 +61,22 @@ char ** create_str_array(size_t count, ...); #define RUN_TEST(testcase) \ do { \ + int success = 1; \ printf("Running test " #testcase " ... \n"); \ - int rc = EXIT_SUCCESS; \ if (!init()) { \ printf("FAILED: initialization of testcase %s at %s:%d\n", #testcase, __FILE__, __LINE__); \ - rc = EXIT_FAILURE; \ + success = 0; \ } else \ if (!testcase) { \ printf("FAILED: testcase %s at %s:%d\n", #testcase, __FILE__, __LINE__); \ - rc = EXIT_FAILURE; \ + success = 0; \ } \ - if (!cleanup(rc == EXIT_SUCCESS)) { \ + if (!cleanup(success)) { \ printf("FAILED: deitialization of testcase %s at %s:%d\n", #testcase, __FILE__, __LINE__); \ - rc = EXIT_FAILURE; \ + success = 0; \ } \ - if (rc != EXIT_SUCCESS) \ - return rc; \ + if (!success) \ + errors++; \ } while(false) #define VERIFY_PRINT_MSG(fmt, actual_str, actual, expected_str, expected, expected_to_be_message) \