Repository: microsoft/ptvsd

Issue:
Clicking Pause should pause all threads
This has been discussed a number of times with @karthiknadig and @huguesv 
Currently clicking Pause doesn't seem to pause all threads.
Note: The requirement to pause all threads is something that comes from VS. (in VSC we'd like to implement the same functionality as we'd need to be consistent).

@karthiknadig I couldn't find an issue that tracks this. Please feel free to close this if there is one.




Discussion:
#72 is probably somewhat relevant.
The difference here is VS passes `threadid = 0` and we use that:
https://github.com/Microsoft/ptvsd/blob/master/ptvsd/wrapper.py#L1568

VSC however, passes specific thread ids.
Note: Going forward we should get rid of this condition as the decision is to ensure both VS and VSC suspend all threads when hitting `Pause`.

Resolving patch:
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -1622,12 +1622,8 @@ def on_pause(self, request, args):
                 )
                 return
 
-        vsc_tid = int(args['threadId'])
-        if vsc_tid == 0:  # VS does this to mean "stop all threads":
-            for pyd_tid in self.thread_map.pydevd_ids():
-                self.pydevd_notify(pydevd_comm.CMD_THREAD_SUSPEND, pyd_tid)
-        else:
-            pyd_tid = self.thread_map.to_pydevd(vsc_tid)
+        # Always suspend all threads.
+        for pyd_tid in self.thread_map.pydevd_ids():
             self.pydevd_notify(pydevd_comm.CMD_THREAD_SUSPEND, pyd_tid)
         self.send_response(request)
 


Test patch:
diff --git a/tests/highlevel/__init__.py b/tests/highlevel/__init__.py
--- a/tests/highlevel/__init__.py
+++ b/tests/highlevel/__init__.py
@@ -805,6 +805,15 @@ def assert_received(self, daemon, expected):
         expected = list(daemon.protocol.parse_each(expected))
         self.assertEqual(received, expected)
 
+    def assert_received_unordered_payload(self, daemon, expected):
+        """Ensure that the received messages match the expected ones
+        regardless of payload order."""
+        received = sorted(m.payload for m in
+                          daemon.protocol.parse_each(daemon.received))
+        expected = sorted(m.payload for m in
+                          daemon.protocol.parse_each(expected))
+        self.assertEqual(received, expected)
+
 
 class HighlevelTest(VSCTest):
     """The base mixin class for high-level ptvsd tests."""
diff --git a/tests/highlevel/test_messages.py b/tests/highlevel/test_messages.py
--- a/tests/highlevel/test_messages.py
+++ b/tests/highlevel/test_messages.py
@@ -729,10 +729,10 @@ class PauseTests(NormalRequestTest, unittest.TestCase):
     PYDEVD_CMD = CMD_THREAD_SUSPEND
     PYDEVD_RESP = None
 
-    def test_pause_one(self):
+    def test_pause(self):
         with self.launched():
             with self.hidden():
-                threads = self.set_threads('spam', 'eggs')
+                threads = self.set_threads('spam', 'eggs', 'abc')
             tid, thread = threads[0]
             self.send_request(
                 threadId=tid,
@@ -743,14 +743,12 @@ def test_pause_one(self):
             self.expected_response(),
             # no events
         ])
-        self.assert_received(self.debugger, [
-            self.expected_pydevd_request(str(thread.id)),
-        ])
 
-    # TODO: finish!
-    @unittest.skip('not finished')
-    def test_pause_all(self):
-        raise NotImplementedError
+        expected = [self.expected_pydevd_request('1')]
+        for _, t in threads:
+            expected.append(self.expected_pydevd_request(str(t.id)))
+
+        self.assert_received_unordered_payload(self.debugger, expected)
 
 
 class ContinueTests(NormalRequestTest, unittest.TestCase):