From e8942d7f22a94a1ecf181eb04637536c71ada922 Mon Sep 17 00:00:00 2001 From: fedepell Date: Fri, 11 Nov 2016 11:07:52 +0100 Subject: [PATCH] waf_unit_test: add new option --dump-test-runner that creates python scripts to manually run or debug test executions this can be very useful when debugging unit test problems as when run outside waf then the LD_LIBRARY_PATH (or PYTHONPATH if used with pytest extra) is set dynamically by waf and therefore running the executable manually or via gdb is not immediate all the environment will be dumped in python script that can then be executed to run manually tests. --- waflib/Tools/waf_unit_test.py | 48 ++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/waflib/Tools/waf_unit_test.py b/waflib/Tools/waf_unit_test.py index a2f34a31..17983302 100644 --- a/waflib/Tools/waf_unit_test.py +++ b/waflib/Tools/waf_unit_test.py @@ -31,9 +31,13 @@ the predefined callback:: bld(features='cxx cxxprogram test', source='main.c', target='app') from waflib.Tools import waf_unit_test bld.add_post_fun(waf_unit_test.summary) + +By passing --dump-test-runner the execution will also create in the build directory a python file named as the task name with -run.py appended +that can be executed manually to reproduce the exact execution manually for debugging purposes. +If the script is run with arguments these will be used instead of the command itself. This can be used to run for example a debugger or profiler on the test manually. """ -import os +import os, sys from waflib.TaskGen import feature, after_method, taskgen_method from waflib import Utils, Task, Logs, Options from waflib.Tools import ccroot @@ -151,6 +155,13 @@ class utest(Task.Task): def exec_command(self, cmd, **kw): Logs.debug('runner: %r', cmd) + if getattr(Options.options, 'dump_test_runner', False): + if not self.generator.name: + Logs.warn('waf_unit_test: --dump-test-runner task with no name, outputs may collide') + runnername=os.path.join(str(self.generator.path.get_bld()), ( "%s-run.py" % (self.generator.name or 'dump-test-runner'))) + Utils.writef(runnername, ENVFILE_TEXT % { 'pyexe': sys.executable, 'env': self.get_test_env(), 'cwd': self.get_cwd().abspath(), 'cmd': cmd[0], 'cmdline': cmd }) + os.chmod(runnername, Utils.O755) + proc = Utils.subprocess.Popen(cmd, cwd=self.get_cwd().abspath(), env=self.get_test_env(), stderr=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE) (stdout, stderr) = proc.communicate() @@ -224,4 +235,39 @@ def options(opt): help = 'Run the unit tests using the test-cmd string' ' example "--test-cmd="valgrind --error-exitcode=1' ' %s" to run under valgrind', dest='testcmd') + opt.add_option('--dump-test-runner', action='store_true', default=False, + help='Create a python script with full environment to run the test manually for debugging purposes', dest='dump_test_runner') + + +""" +ENVFILE_TEXT specifies the contents of the test runner script generated if +--dump-test-runner is used. This can be used to manually run tests which are +failing in the exact environment as waf tests are run. +By default when executed it will just run the test and exit. If any arguments +are passed then those are executed. The use case is for example to pass +'bash' and this will open the shell when gdb can then be used in the same +environment as waf would have run the test. +Test command line is exported as $UT_CMDLINE so this can be used inside the +executed environment. +To execute directly gdb something like 'bash -c "gdb \$UT_CMDLINE"' can be +specified as argument as well. +""" +ENVFILE_TEXT = """#! %(pyexe)s +# If executed with no parametrs the script will run the test exactly as waf +# If parameters are passed they will be executed instead but in a waf-like +# environment. Example executions: +# Create a shell when you can manually invoke gdb or other tools: +#