diff --git a/tests/helpers/debugadapter.py b/tests/helpers/debugadapter.py index 900b2e00a..aca6f248f 100644 --- a/tests/helpers/debugadapter.py +++ b/tests/helpers/debugadapter.py @@ -53,6 +53,13 @@ ] +try: + ConnectionRefusedError +except Exception: + class ConnectionRefusedError(Exception): + pass + + def _copy_env(verbose=False, env=None): variables = {k: v for k, v in os.environ.items() if k in COPIED_ENV} # TODO: Be smarter about the seed? diff --git a/tests/resources/system_tests/test_basic/test_args/mymod_launch1/__init__.py b/tests/resources/system_tests/test_basic/test_args/mypkg_launch1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_basic/test_args/mymod_launch1/__init__.py rename to tests/resources/system_tests/test_basic/test_args/mypkg_launch1/__init__.py diff --git a/tests/resources/system_tests/test_basic/test_args/mymod_launch1/__main__.py b/tests/resources/system_tests/test_basic/test_args/mypkg_launch1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_basic/test_args/mymod_launch1/__main__.py rename to tests/resources/system_tests/test_basic/test_args/mypkg_launch1/__main__.py diff --git a/tests/resources/system_tests/test_basic/test_output/mymod_attach1/__init__.py b/tests/resources/system_tests/test_basic/test_output/mypkg_attach1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_basic/test_output/mymod_attach1/__init__.py rename to tests/resources/system_tests/test_basic/test_output/mypkg_attach1/__init__.py diff --git a/tests/resources/system_tests/test_basic/test_output/mymod_attach1/__main__.py b/tests/resources/system_tests/test_basic/test_output/mypkg_attach1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_basic/test_output/mymod_attach1/__main__.py rename to tests/resources/system_tests/test_basic/test_output/mypkg_attach1/__main__.py diff --git a/tests/resources/system_tests/test_basic/test_output/mymod_launch1/__init__.py b/tests/resources/system_tests/test_basic/test_output/mypkg_launch1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_basic/test_output/mymod_launch1/__init__.py rename to tests/resources/system_tests/test_basic/test_output/mypkg_launch1/__init__.py diff --git a/tests/resources/system_tests/test_basic/test_output/mymod_launch1/__main__.py b/tests/resources/system_tests/test_basic/test_output/mypkg_launch1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_basic/test_output/mymod_launch1/__main__.py rename to tests/resources/system_tests/test_basic/test_output/mypkg_launch1/__main__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_foo/__init__.py b/tests/resources/system_tests/test_breakpoints/mymod_foo/__init__.py deleted file mode 100644 index 4c33a5ce7..000000000 --- a/tests/resources/system_tests/test_breakpoints/mymod_foo/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import mymod_bar.bar - - -def do_foo(): - mymod_bar.bar.do_bar() - - -do_foo() diff --git a/tests/resources/system_tests/test_breakpoints/mymod_attach1/__init__.py b/tests/resources/system_tests/test_breakpoints/mypkg_attach1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_attach1/__init__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_attach1/__init__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_attach1/__main__.py b/tests/resources/system_tests/test_breakpoints/mypkg_attach1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_attach1/__main__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_attach1/__main__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_bar/__init__.py b/tests/resources/system_tests/test_breakpoints/mypkg_bar/__init__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_bar/__init__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_bar/__init__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_bar/__main__.py b/tests/resources/system_tests/test_breakpoints/mypkg_bar/__main__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_bar/__main__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_bar/__main__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_bar/bar.py b/tests/resources/system_tests/test_breakpoints/mypkg_bar/bar.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_bar/bar.py rename to tests/resources/system_tests/test_breakpoints/mypkg_bar/bar.py diff --git a/tests/resources/system_tests/test_breakpoints/mypkg_foo/__init__.py b/tests/resources/system_tests/test_breakpoints/mypkg_foo/__init__.py new file mode 100644 index 000000000..ff77fe668 --- /dev/null +++ b/tests/resources/system_tests/test_breakpoints/mypkg_foo/__init__.py @@ -0,0 +1,8 @@ +import mypkg_bar.bar + + +def do_foo(): + mypkg_bar.bar.do_bar() + + +do_foo() diff --git a/tests/resources/system_tests/test_breakpoints/mymod_foo/__main__.py b/tests/resources/system_tests/test_breakpoints/mypkg_foo/__main__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_foo/__main__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_foo/__main__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_launch1/__init__.py b/tests/resources/system_tests/test_breakpoints/mypkg_launch1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_launch1/__init__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_launch1/__init__.py diff --git a/tests/resources/system_tests/test_breakpoints/mymod_launch1/__main__.py b/tests/resources/system_tests/test_breakpoints/mypkg_launch1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_breakpoints/mymod_launch1/__main__.py rename to tests/resources/system_tests/test_breakpoints/mypkg_launch1/__main__.py diff --git a/tests/resources/system_tests/test_exceptions/mymod_attach1/__init__.py b/tests/resources/system_tests/test_exceptions/mypkg_attach1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_exceptions/mymod_attach1/__init__.py rename to tests/resources/system_tests/test_exceptions/mypkg_attach1/__init__.py diff --git a/tests/resources/system_tests/test_exceptions/mymod_attach1/__main__.py b/tests/resources/system_tests/test_exceptions/mypkg_attach1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_exceptions/mymod_attach1/__main__.py rename to tests/resources/system_tests/test_exceptions/mypkg_attach1/__main__.py diff --git a/tests/resources/system_tests/test_exceptions/mymod_launch1/__init__.py b/tests/resources/system_tests/test_exceptions/mypkg_launch1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_exceptions/mymod_launch1/__init__.py rename to tests/resources/system_tests/test_exceptions/mypkg_launch1/__init__.py diff --git a/tests/resources/system_tests/test_exceptions/mymod_launch1/__main__.py b/tests/resources/system_tests/test_exceptions/mypkg_launch1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_exceptions/mymod_launch1/__main__.py rename to tests/resources/system_tests/test_exceptions/mypkg_launch1/__main__.py diff --git a/tests/resources/system_tests/test_forever/attach_forever.py b/tests/resources/system_tests/test_forever/attach_forever.py new file mode 100644 index 000000000..a6f395ff2 --- /dev/null +++ b/tests/resources/system_tests/test_forever/attach_forever.py @@ -0,0 +1,11 @@ +import ptvsd +import sys +import time + +ptvsd.enable_attach((sys.argv[1], sys.argv[2])) + +i = 0 +while True: + time.sleep(0.1) + print(i) + i += 1 diff --git a/tests/resources/system_tests/test_terminate/mymod_launch1/__init__.py b/tests/resources/system_tests/test_terminate/mypkg_launch1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_terminate/mymod_launch1/__init__.py rename to tests/resources/system_tests/test_terminate/mypkg_launch1/__init__.py diff --git a/tests/resources/system_tests/test_terminate/mymod_launch1/__main__.py b/tests/resources/system_tests/test_terminate/mypkg_launch1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_terminate/mymod_launch1/__main__.py rename to tests/resources/system_tests/test_terminate/mypkg_launch1/__main__.py diff --git a/tests/resources/system_tests/test_variables/mymod_attach1/__init__.py b/tests/resources/system_tests/test_variables/mypkg_attach1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_variables/mymod_attach1/__init__.py rename to tests/resources/system_tests/test_variables/mypkg_attach1/__init__.py diff --git a/tests/resources/system_tests/test_variables/mymod_attach1/__main__.py b/tests/resources/system_tests/test_variables/mypkg_attach1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_variables/mymod_attach1/__main__.py rename to tests/resources/system_tests/test_variables/mypkg_attach1/__main__.py diff --git a/tests/resources/system_tests/test_variables/mymod_launch1/__init__.py b/tests/resources/system_tests/test_variables/mypkg_launch1/__init__.py similarity index 100% rename from tests/resources/system_tests/test_variables/mymod_launch1/__init__.py rename to tests/resources/system_tests/test_variables/mypkg_launch1/__init__.py diff --git a/tests/resources/system_tests/test_variables/mymod_launch1/__main__.py b/tests/resources/system_tests/test_variables/mypkg_launch1/__main__.py similarity index 100% rename from tests/resources/system_tests/test_variables/mymod_launch1/__main__.py rename to tests/resources/system_tests/test_variables/mypkg_launch1/__main__.py diff --git a/tests/system_tests/__init__.py b/tests/system_tests/__init__.py index 18b0e30e6..5574bc1f6 100644 --- a/tests/system_tests/__init__.py +++ b/tests/system_tests/__init__.py @@ -2,7 +2,9 @@ import os import ptvsd import signal +import sys import time +import traceback import unittest from collections import namedtuple @@ -234,24 +236,46 @@ def _kill_proc(pid): pass time.sleep(1) # wait for socket connections to die out. - def _wrap_and_reraise(ex, session): + def _wrap_and_reraise(session, ex, exc_type, exc_value, exc_traceback): + """If we have connetion errors, then re-raised wrapped in + ConnectionTimeoutError. If using py3, then chain exceptions so + we do not loose the original exception, else try hack approach + for py27.""" messages = [] + formatted_ex = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) # noqa try: messages = [str(msg) for msg in _strip_newline_output_events(session.received)] except Exception: pass - messages = os.linesep.join(messages) + fmt = { + "sep": os.linesep, + "messages": os.linesep.join(messages), + "error": ''.join(traceback.format_exception_only(exc_type, exc_value)) # noqa + } + message = """ + +Session Messages: +----------------- +%(messages)s + +Original Error: +--------------- +%(error)s""" % fmt + try: - raise Exception(messages) from ex - except Exception: - print(messages) - raise ex + # Chain the original exception for py3. + exec('raise Exception(message) from ex', globals(), locals()) + except SyntaxError: + # This happens when using py27. + message = message + os.linesep + formatted_ex + exec("raise Exception(message)", globals(), locals()) def _handle_exception(ex, adapter, session): + exc_type, exc_value, exc_traceback = sys.exc_info() _kill_proc(adapter.pid) - _wrap_and_reraise(ex, session) + _wrap_and_reraise(session, ex, exc_type, exc_value, exc_traceback) if debug_info.attachtype == 'import' and \ debug_info.modulename is not None: diff --git a/tests/system_tests/test_remote.py b/tests/system_tests/test_remote.py index 255238e0d..2a98b1227 100644 --- a/tests/system_tests/test_remote.py +++ b/tests/system_tests/test_remote.py @@ -1,5 +1,6 @@ import os import os.path +import time from tests.helpers.resource import TestResources from tests.helpers.socket import resolve_hostname @@ -28,6 +29,39 @@ def run_test_attach(self, debug_info): self.new_event('output', category='stderr', output='no'), ]) + def run_test_source_references(self, + debug_info, + expected_stacktrace, + path_mappings=[], + debug_options=[]): + options = { + "debugOptions": ["RedirectOutput"] + debug_options, + "pathMappings": path_mappings + } + + with self.start_debugging(debug_info) as dbg: + (_, req_attach, _, _, _, req_threads) = lifecycle_handshake( + dbg.session, + debug_info.starttype, + options=options, + threads=True) + + # wait till we enter the for loop. + time.sleep(1) + Awaitable.wait_all(req_attach, req_threads) + with dbg.session.wait_for_event("stopped") as result: + dbg.session.send_request('pause') + sdf + tid = result["msg"].body["threadId"] + stacktrace = dbg.session.send_request("stackTrace", threadId=tid) + stacktrace.wait() + dbg.session.send_request("continue", threadId=tid).wait() + + # Kill remove program. + os.kill(dbg.adapter.pid, signal.SIGKILL) + + self.assert_is_subset(stacktrace.resp, expected_stacktrace) + class AttachFileTests(RemoteTests): @@ -86,6 +120,129 @@ def test_attach_byip(self): host=ip, cwd=cwd, starttype='attach', - argv=argv, - ), - ) + argv=argv)) + + def test_source_references_should_be_returned_without_path_mappings(self): + filename = os.path.join(TEST_FORVER_FILES_DIR, 'attach_forever.py') + cwd = os.path.dirname(filename) + argv = ['localhost', str(PORT)] + expected_stacktrace = { + "stackFrames": [{ + "source": { + "path": filename, + "sourceReference": 1 + } + }], + } + self.run_test_source_references( + DebugInfo( + filename=filename, + attachtype='import', + cwd=cwd, + starttype='attach', + argv=argv), expected_stacktrace) + + def test_source_references_should_not_be_returned_with_path_mappings(self): + filename = os.path.join(TEST_FORVER_FILES_DIR, 'attach_forever.py') + cwd = os.path.dirname(filename) + argv = ['localhost', str(PORT)] + path_mappings = [{ + "localRoot": os.path.dirname(filename), + "remoteRoot": os.path.dirname(filename) + }] + expected_stacktrace = { + "stackFrames": [{ + "source": { + "path": filename, + "sourceReference": 0 + } + }], + } + self.run_test_source_references( + DebugInfo( + filename=filename, + attachtype='import', + cwd=cwd, + starttype='attach', + argv=argv), expected_stacktrace, path_mappings) + + def test_source_references_should_be_returned_with_invalid_path_mappings( + self): + filename = os.path.join(TEST_FORVER_FILES_DIR, 'attach_forever.py') + cwd = os.path.dirname(filename) + argv = ['localhost', str(PORT)] + path_mappings = [{ + "localRoot": TEST_FILES_DIR, + "remoteRoot": TEST_FILES_DIR + }] + expected_stacktrace = { + "stackFrames": [{ + "source": { + "path": filename, + "sourceReference": 1 + } + }], + } + self.run_test_source_references( + DebugInfo( + filename=filename, + attachtype='import', + cwd=cwd, + starttype='attach', + argv=argv), expected_stacktrace, path_mappings) + + def test_source_references_should_be_returned_with_win_client(self): + filename = os.path.join(TEST_FORVER_FILES_DIR, 'attach_forever.py') + cwd = os.path.dirname(filename) + argv = ['localhost', str(PORT)] + client_dir = 'C:\\Development\\Projects\\src\\sub dir' + path_mappings = [{ + "localRoot": client_dir, + "remoteRoot": os.path.dirname(filename) + }] + expected_stacktrace = { + "stackFrames": [{ + "source": { + "path": client_dir + '\\' + os.path.basename(filename), + "sourceReference": 0 + } + }], + } + self.run_test_source_references( + DebugInfo( + filename=filename, + attachtype='import', + cwd=cwd, + starttype='attach', + argv=argv), + expected_stacktrace, + path_mappings=path_mappings, + debug_options=['WindowsClient']) + + @unittest.skipIf(sys.platform == 'win32', 'Run only on Unix clients') + def test_source_references_should_be_returned_with_unix_client(self): + filename = os.path.join(TEST_FORVER_FILES_DIR, 'attach_forever.py') + cwd = os.path.dirname(filename) + argv = ['localhost', str(PORT)] + client_dir = '/Users/PeterSmith/projects/src/sub dir' + path_mappings = [{ + "localRoot": client_dir, + "remoteRoot": os.path.dirname(filename) + }] + expected_stacktrace = { + "stackFrames": [{ + "source": { + "path": client_dir + '/' + os.path.basename(filename), + "sourceReference": 0 + } + }], + } + self.run_test_source_references( + DebugInfo( + filename=filename, + attachtype='import', + cwd=cwd, + starttype='attach', + argv=argv), + expected_stacktrace, + path_mappings=path_mappings)