validate: Implement support to run tests inside gdb
authorThibault Saunier <tsaunier@gnome.org>
Tue, 10 Nov 2015 16:43:54 +0000 (17:43 +0100)
committerThibault Saunier <tsaunier@gnome.org>
Tue, 10 Nov 2015 17:17:54 +0000 (18:17 +0100)
Making debugging races leading to crashes easier to debug

validate/launcher/baseclasses.py
validate/launcher/main.py

index 7b0f2e1..6a4ef35 100644 (file)
@@ -40,7 +40,7 @@ from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \
 
 # The factor by which we increase the hard timeout when running inside
 # Valgrind
-VALGRIND_TIMEOUT_FACTOR = 20
+GDB_TIMEOUT_FACTOR = VALGRIND_TIMEOUT_FACTOR = 20
 # The error reported by valgrind when detecting errors
 VALGRIND_ERROR_CODE = 20
 
@@ -186,12 +186,19 @@ class Test(Loggable):
     def set_result(self, result, message="", error=""):
         self.debug("Setting result: %s (message: %s, error: %s)" % (result,
                    message, error))
+
         if result is Result.TIMEOUT and self.options.debug is True:
-            pname = subprocess.check_output(("readlink -e /proc/%s/exe"
-                                             % self.process.pid).split(' ')).replace('\n', '')
-            raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n"
-                      "Press enter to continue" % (Colors.FAIL, pname, self.process.pid,
-                                                   Colors.ENDC))
+            if self.options.gdb:
+                printc("Timeout, you should process <ctrl>c to get into gdb",
+                       Colors.FAIL)
+                # and wait here until gdb exits
+                self.process.communicate()
+            else:
+                pname = subprocess.check_output(("readlink -e /proc/%s/exe"
+                                                 % self.process.pid).split(' ')).replace('\n', '')
+                raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n"
+                          "Press enter to continue" % (Colors.FAIL, pname, self.process.pid,
+                                                       Colors.ENDC))
 
         self.result = result
         self.message = message
@@ -307,6 +314,12 @@ class Test(Loggable):
     def get_valgrind_suppressions(self):
         return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')]
 
+    def use_gdb(self):
+        if self.hard_timeout is not None:
+            self.hard_timeout *= GDB_TIMEOUT_FACTOR
+        self.timeout *= GDB_TIMEOUT_FACTOR
+        self.command = "gdb -ex run -ex quit --args %s" % self.command
+
     def use_valgrind(self):
         vglogsfile = self.logfile + '.valgrind'
         self.extra_logfiles.append(vglogsfile)
@@ -364,6 +377,9 @@ class Test(Loggable):
             self.proc_env[var] = self.proc_env.get(var, '') + os.pathsep + value
             self.add_env_variable(var, self.proc_env[var])
 
+        if self.options.gdb:
+            self.use_gdb()
+
         if self.options.valgrind:
             self.use_valgrind()
 
index b1b8cc8..4ce4087 100644 (file)
@@ -192,6 +192,7 @@ class LauncherConfig(Loggable):
         self.long_limit = utils.LONG_TEST
         self.config = None
         self.valgrind = False
+        self.gdb = False
         self.no_display = False
         self.xunit_file = None
         self.main_dir = utils.DEFAULT_MAIN_DIR
@@ -230,6 +231,17 @@ class LauncherConfig(Loggable):
         else:
             self.output_dir = os.path.abspath(self.output_dir)
 
+        if self.gdb:
+            self.logsdir = "stdout"
+            self.debug = True
+            self.num_jobs = 1
+            try:
+                subprocess.check_output("gdb --help", shell=True)
+            except subprocess.CalledProcessError:
+                printc("Want to use gdb, but not avalaible on the system",
+                       Colors.FAIL)
+                return False
+
         # other output directories
         if self.logsdir in ['stdout', 'stderr']:
             # Allow -l stdout/stderr to work like -rl stdout/stderr
@@ -403,6 +415,10 @@ Note that all testsuite should be inside python modules, so the directory should
     parser.add_argument("-vg", "--valgrind", dest="valgrind",
                         action="store_true",
                         help="Run the tests inside Valgrind")
+    parser.add_argument("--gdb", dest="gdb",
+                        action="store_true",
+                        help="Run the tests inside gdb (implies"
+                        " --output-dir=stdout and --jobs=1)")
     parser.add_argument("-nd", "--no-display", dest="no_display",
                         action="store_true",
                         help="Run the tests without outputting graphics"