From eb50bc29dfed21683a5bfad50ee027afc0964c6c Mon Sep 17 00:00:00 2001 From: Pavel Minaev Date: Fri, 13 Dec 2019 13:28:01 -0800 Subject: [PATCH] Disable attach tests on macOS + Python 3.6 due to #1967 Gracefully handle server abruptly disconnecting from adapter for the initial connection. Fix test_exclude_rules to wait until debuggee terminates. --- src/ptvsd/adapter/servers.py | 24 ++++++++++++++++++++---- tests/debug/session.py | 5 +++++ tests/ptvsd/server/test_attach.py | 1 + tests/ptvsd/server/test_exclude_rules.py | 2 ++ tests/ptvsd/server/test_multiproc.py | 2 -- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/ptvsd/adapter/servers.py b/src/ptvsd/adapter/servers.py index a59931a6..7a1db34d 100644 --- a/src/ptvsd/adapter/servers.py +++ b/src/ptvsd/adapter/servers.py @@ -43,6 +43,8 @@ class Connection(sockets.ClientConnection): def __init__(self, sock): from ptvsd.adapter import sessions + self.disconnected = False + self.server = None """The Server component, if this debug server belongs to Session. """ @@ -101,6 +103,13 @@ if 'ptvsd' not in sys.modules: log.exception("Failed to inject ptvsd into {0}:", self, level="warning") with _lock: + # The server can disconnect concurrently before we get here, e.g. if + # it was force-killed. If the disconnect() handler has already run, + # don't register this server or report it, since there's nothing to + # deregister it. + if self.disconnected: + return + if any(conn.pid == self.pid for conn in _connections): raise KeyError( fmt("{0} is already connected to this adapter", self) @@ -110,10 +119,16 @@ if 'ptvsd' not in sys.modules: except Exception: log.exception("Failed to accept incoming server connection:") + self.channel.close() + + # If this was the first server to connect, and the main thread is inside + # wait_until_disconnected(), we want to unblock it and allow it to exit. + with _lock: + _connections_changed.set() + # If we couldn't retrieve all the necessary info from the debug server, # or there's a PID clash, we don't want to track this debuggee anymore, # but we want to continue accepting connections. - self.channel.close() return parent_session = sessions.get(self.ppid) @@ -155,10 +170,11 @@ if 'ptvsd' not in sys.modules: def disconnect(self): with _lock: - # If the disconnect happened while Server was being instantiated, we need - # to tell it, so that it can clean up properly via Session.finalize(). It - # will also take care of deregistering the connection in that case. + self.disconnected = True if self.server is not None: + # If the disconnect happened while Server was being instantiated, + # we need to tell it, so that it can clean up via Session.finalize(). + # It will also take care of deregistering the connection in that case. self.server.disconnect() elif self in _connections: _connections.remove(self) diff --git a/tests/debug/session.py b/tests/debug/session.py index 03926dd4..8ee8e9c8 100644 --- a/tests/debug/session.py +++ b/tests/debug/session.py @@ -9,6 +9,7 @@ import itertools import os import psutil import py +import pytest import subprocess import sys import time @@ -442,6 +443,10 @@ class Session(object): ) def send_request(self, command, arguments=None, proceed=True): + if command == "attach": + if sys.version_info[:2] == (3, 6) and sys.platform == "darwin": + pytest.skip("https://github.com/microsoft/ptvsd/issues/1967") + self.before_request(command, arguments) if self.timeline.is_frozen and proceed: diff --git a/tests/ptvsd/server/test_attach.py b/tests/ptvsd/server/test_attach.py index 50037697..e1b17e20 100644 --- a/tests/ptvsd/server/test_attach.py +++ b/tests/ptvsd/server/test_attach.py @@ -148,6 +148,7 @@ def test_attach_by_pid(pyfile, target, pid_type): break with debug.Session() as session: + def before_request(command, arguments): if command == "attach": assert isinstance(arguments["processId"], int) diff --git a/tests/ptvsd/server/test_exclude_rules.py b/tests/ptvsd/server/test_exclude_rules.py index 1080670c..b2bc30c4 100644 --- a/tests/ptvsd/server/test_exclude_rules.py +++ b/tests/ptvsd/server/test_exclude_rules.py @@ -57,6 +57,8 @@ def test_exceptions_and_exclude_rules(pyfile, target, run, scenario, exc_type): ) # No exceptions should be seen. + session.wait_for_next_event("terminated") + session.proceed() @pytest.mark.parametrize("scenario", ["exclude_code_to_debug", "exclude_callback_dir"]) diff --git a/tests/ptvsd/server/test_multiproc.py b/tests/ptvsd/server/test_multiproc.py index 8cf105a3..95245c83 100644 --- a/tests/ptvsd/server/test_multiproc.py +++ b/tests/ptvsd/server/test_multiproc.py @@ -13,8 +13,6 @@ from tests import debug from tests.debug import runners from tests.patterns import some -pytestmark = pytest.mark.timeout(30) - @pytest.fixture(params=[runners.launch, runners.attach_by_socket["api"]]) def run(request):