[lldb] [test] Fix TestGdbRemote_vContThreads.py logic
authorMichał Górny <mgorny@moritz.systems>
Tue, 16 Mar 2021 23:04:06 +0000 (00:04 +0100)
committerMichał Górny <mgorny@moritz.systems>
Wed, 17 Mar 2021 16:30:28 +0000 (17:30 +0100)
The TestGdbRemote_vContThreads.py were introduced to test NetBSD process
plugin's capability of sending per-thread and per-process signals.
However, at some point the tests started failing.  From retrospective,
it is possible that they were relying on some bug in the plugin's
original signal handling.

Fix the tests not to expect the process to terminate after receiving
the signals.  Instead, scan for output indicating that the signals were
received and match thread IDs in it.  Enable 'signal to all threads'
test everywhere as it works fine on Linux.  Add a new test for vCont
packet without specific thread IDs.  Introduce a helper function
to cover the common part of tests.

While this does not fix all the problems on NetBSD, it enables a subset
of the tests on other systems.  I am planning to add more tests
to the group while implementing multiprocess extension for vCont.

Differential Revision: https://reviews.llvm.org/D98749

lldb/test/API/tools/lldb-server/TestGdbRemote_vContThreads.py

index 5278d59..9243f71 100644 (file)
@@ -31,6 +31,34 @@ class TestGdbRemote_vContThreads(gdbremote_testcase.GdbRemoteTestCaseBase):
         self.reset_test_sequence()
         return threads
 
+    def send_and_check_signal(self, vCont_data, threads):
+        self.test_sequence.add_log_lines([
+            "read packet: $vCont;{0}#00".format(vCont_data),
+            {"type": "output_match",
+             "regex": self.maybe_strict_output_regex(
+                 len(threads) *
+                 r"received SIGUSR1 on thread id: ([0-9a-f]+)\r\n"),
+             "capture": dict((i, "tid{0}".format(i)) for i
+                             in range(1, len(threads)+1)),
+             },
+        ], True)
+
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+        tids = sorted(int(context["tid{0}".format(x)], 16)
+                      for x in range(1, len(threads)+1))
+        self.assertEqual(tids, sorted(threads))
+
+    @expectedFailureNetBSD
+    def test_signal_process_without_tid(self):
+        self.build()
+        self.set_inferior_startup_launch()
+
+        threads = self.start_threads(1)
+        self.send_and_check_signal(
+            "C{0:x}".format(lldbutil.get_signal_number('SIGUSR1')),
+            threads)
+
     @skipUnlessPlatform(["netbsd"])
     @expectedFailureNetBSD
     def test_signal_one_thread(self):
@@ -39,16 +67,10 @@ class TestGdbRemote_vContThreads(gdbremote_testcase.GdbRemoteTestCaseBase):
 
         threads = self.start_threads(1)
         # try sending a signal to one of the two threads
-        self.test_sequence.add_log_lines([
-            "read packet: $vCont;C{0:x}:{1:x};c#00".format(
-                lldbutil.get_signal_number('SIGUSR1'), threads[0]),
-            {"direction": "send", "regex": r"^\$W00#b7$"},
-        ], True)
-
-        context = self.expect_gdbremote_sequence()
-        self.assertIsNotNone(context)
+        self.send_and_check_signal(
+            "C{0:x}:{1:x};c".format(lldbutil.get_signal_number('SIGUSR1')),
+            threads[:1])
 
-    @skipUnlessPlatform(["netbsd"])
     @expectedFailureNetBSD
     def test_signal_all_threads(self):
         self.build()
@@ -56,15 +78,11 @@ class TestGdbRemote_vContThreads(gdbremote_testcase.GdbRemoteTestCaseBase):
 
         threads = self.start_threads(1)
         # try sending a signal to two threads (= the process)
-        self.test_sequence.add_log_lines([
-            "read packet: $vCont;C{0:x}:{1:x};C{0:x}:{2:x}#00".format(
+        self.send_and_check_signal(
+            "C{0:x}:{1:x};C{0:x}:{2:x}".format(
                 lldbutil.get_signal_number('SIGUSR1'),
-                threads[0], threads[1]),
-            {"direction": "send", "regex": r"^\$W00#b7$"},
-        ], True)
-
-        context = self.expect_gdbremote_sequence()
-        self.assertIsNotNone(context)
+                *threads),
+            threads)
 
     @skipUnlessPlatform(["netbsd"])
     def test_signal_two_of_three_threads(self):