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.
This only happens when sudo unloads the last python plugin.
The reason doing so is because there are some python modules which
does not support importing them again after destroying the interpreter
which has imported them previously.
Another solution would be to just leak the interpreters (let the kernel
free up), but then there might be some python resources like open files
would not get cleaned up correctly if the plugin is badly written.
Tests are meant to test the scenario sudo does, so I have modified them
to generally do not unlink but only a few times (~per plugin type) so it
does not use 48 interpreters (one gets started on every plugin->open) and
it is visible at least which type of plugin fails deinit if there is an
error.
It is a bit more code, but it is more "pythonic" and easier to debug
as the enum values also know their names.
It is also an API break, eg. sudo.RC_OK becomes sudo.RC.OK as sudo.RC will
be the "type" of the enum, but I guess that is acceptable before the
initial release.
On each plugin initialization we create a separate python interpreter
which gets stored in the plugin_ctx. The main interpreter is
stored in py_ctx and is used for creating more interpreters (if more plugins
get loaded) and final python deinitialization.
The "traceback" module import and the ImportBlocker initialization was
moved, because it has to happen inside the plugin specific interpreters.
Adapted the default sudo_printf from sudoers plugin to be able to print
errors before plugin open() gets called. (This is used by the multiple io
plugin loading to display error for too much plugin load.)
Since this makes us always have a sudo_log, I have removed the logic about
whether it is available or not.