Add start method import (#1004)

* Add unicode tests

* Fix breakpoint for unicode test

* Add ptvsd import test

* Improve how we do import ptvsd tests.

* Enable import ptvsd tests

* Disabling import based test temporaily
This commit is contained in:
Karthik Nadig 2018-11-12 18:35:35 -08:00 committed by GitHub
parent 8b92b8462d
commit 36f2aef119
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 158 additions and 57 deletions

View file

@ -2427,6 +2427,8 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
# as well.
with self.is_process_created_lock:
if not self.is_process_created:
if not debugger_attached.isSet():
return
self.is_process_created = True
self.send_process_event(self.start_reason)

View file

@ -119,6 +119,9 @@ def pyfile(request, tmpdir):
tmpfile = tmpdir.join(name + '.py')
assert not tmpfile.check()
# NOTE: This is a requirement with using pyfile. Adding this
# makes it easier to add import start method
assert 'import_and_enable_debugger' in source
tmpfile.write(source)
return tmpfile.strpath
@ -139,8 +142,8 @@ else:
_ATTACH_PARAMS = [
('launch',),
('attach', 'socket', 'cmdline'),
('attach', 'socket', 'import'),
('attach', 'pid'),
# ('attach', 'socket', 'import'),
# ('attach', 'pid'),
]
_RUN_AS_PARAMS = [

View file

@ -7,25 +7,42 @@ from __future__ import print_function, with_statement, absolute_import
import os.path
import pytest
from pytests.helpers.timeline import Event
import sys
from pytests.helpers.timeline import Event, Response
from pytests.helpers.pathutils import get_test_root, compare_path
from pytests.helpers.session import START_METHOD_LAUNCH, START_METHOD_CMDLINE
BP_TEST_ROOT = get_test_root('bp')
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
def test_path_with_ampersand(debug_session, start_method):
bp_line = 2
def test_path_with_ampersand(debug_session, start_method, run_as):
bp_line = 4
testfile = os.path.join(BP_TEST_ROOT, 'a&b', 'test.py')
debug_session.initialize(target=('file', testfile), start_method=start_method)
debug_session.initialize(target=(run_as, testfile), start_method=start_method)
debug_session.set_breakpoints(testfile, [bp_line])
debug_session.start_debugging()
hit = debug_session.wait_for_thread_stopped()
frames = hit.stacktrace.body['stackFrames']
assert compare_path(frames[0]['source']['path'], testfile, show=False)
debug_session.send_request('continue').wait_for_response()
debug_session.wait_for_next(Event('continued'))
continue_request = debug_session.send_request('continue')
debug_session.wait_for_next(Response(continue_request) & Event('continued'))
debug_session.wait_for_exit()
@pytest.mark.skipif(sys.version_info < (3, 0), reason='Not supported on 2.7')
def test_path_with_unicode(debug_session, start_method, run_as):
bp_line = 6
testfile = os.path.join(BP_TEST_ROOT, u'ನನ್ನ_ಸ್ಕ್ರಿಪ್ಟ್.py')
debug_session.initialize(target=(run_as, testfile), start_method=start_method)
debug_session.set_breakpoints(testfile, [bp_line])
debug_session.start_debugging()
hit = debug_session.wait_for_thread_stopped()
frames = hit.stacktrace.body['stackFrames']
assert compare_path(frames[0]['source']['path'], testfile, show=False)
assert u'ಏನಾದರೂ_ಮಾಡು' == frames[0]['name']
continue_request = debug_session.send_request('continue')
debug_session.wait_for_next(Response(continue_request) & Event('continued'))
debug_session.wait_for_exit()

View file

@ -7,32 +7,32 @@ from __future__ import print_function, with_statement, absolute_import
import pytest
from pytests.helpers.pattern import ANY
from pytests.helpers.timeline import Event
from pytests.helpers.session import START_METHOD_LAUNCH, START_METHOD_CMDLINE
expected_at_line = {
6: [
8: [
{'label': 'SomeClass', 'type': 'class'},
{'label': 'someFunction', 'type': 'function'},
{'label': 'someVariable', 'type': 'field'},
],
9: [
{'label': 'SomeClass', 'type': 'class'},
{'label': 'someFunction', 'type': 'function'},
{'label': 'someVar', 'type': 'field'},
{'label': 'someVariable', 'type': 'field'},
],
11: [
{'label': 'SomeClass', 'type': 'class'},
{'label': 'someFunction', 'type': 'function'},
{'label': 'someVar', 'type': 'field'},
{'label': 'someVariable', 'type': 'field'},
],
13: [
{'label': 'SomeClass', 'type': 'class'},
{'label': 'someFunction', 'type': 'function'},
],
}
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
@pytest.mark.parametrize('bp_line', expected_at_line.keys())
def test_completions_scope(debug_session, pyfile, bp_line, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
class SomeClass():
def __init__(self, someVar):
self.some_var = someVar
@ -83,16 +83,17 @@ def test_completions_scope(debug_session, pyfile, bp_line, run_as, start_method)
debug_session.wait_for_exit()
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
def test_completions(debug_session, pyfile, start_method, run_as):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
a = 1
b = {"one": 1, "two": 2}
c = 3
print([a, b, c])
bp_line = 4
bp_line = 6
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])

View file

@ -4,24 +4,23 @@
from __future__ import print_function, with_statement, absolute_import
import pytest
from pytests.helpers import print
from pytests.helpers.pattern import ANY
from pytests.helpers.timeline import Event
from pytests.helpers.session import START_METHOD_LAUNCH, START_METHOD_CMDLINE
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
def test_variables_and_evaluate(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
a = 1
b = {"one": 1, "two": 2}
c = 3
print([a, b, c])
bp_line = 4
bp_line = 6
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])
@ -101,14 +100,15 @@ def test_variables_and_evaluate(debug_session, pyfile, run_as, start_method):
debug_session.wait_for_exit()
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
def test_set_variable(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
a = 1
print(a)
bp_line = 2
bp_line = 4
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])
@ -154,11 +154,12 @@ def test_set_variable(debug_session, pyfile, run_as, start_method):
debug_session.wait_for_exit()
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
def test_variable_sort(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
b_test = {"spam": "A", "eggs": "B", "abcd": "C"} # noqa
_b_test = 12 # noqa
__b_test = 13 # noqa
@ -174,7 +175,7 @@ def test_variable_sort(debug_session, pyfile, run_as, start_method):
d = 3 # noqa
print('done')
bp_line = 13
bp_line = 15
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])

View file

@ -24,6 +24,8 @@ def test_multiprocessing(debug_session, pyfile, run_as, start_method):
import multiprocessing
import platform
import sys
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
def child_of_child(q):
print('entering child of child')
@ -143,6 +145,8 @@ def test_subprocess(debug_session, pyfile, start_method, run_as):
def child():
import sys
import backchannel
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
backchannel.write_json(sys.argv)
@pyfile
@ -150,6 +154,8 @@ def test_subprocess(debug_session, pyfile, start_method, run_as):
import os
import subprocess
import sys
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
argv = [sys.executable, sys.argv[1], '--arg1', '--arg2', '--arg3']
env = os.environ.copy()
process = subprocess.Popen(argv, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -200,6 +206,8 @@ def test_subprocess(debug_session, pyfile, start_method, run_as):
def test_autokill(debug_session, pyfile, start_method, run_as):
@pyfile
def child():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
while True:
pass
@ -209,6 +217,8 @@ def test_autokill(debug_session, pyfile, start_method, run_as):
import os
import subprocess
import sys
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
argv = [sys.executable, sys.argv[1]]
env = os.environ.copy()
subprocess.Popen(argv, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

View file

@ -12,17 +12,17 @@ import ptvsd
from pytests.helpers import print
from pytests.helpers.pattern import ANY
from pytests.helpers.timeline import Event
from pytests.helpers.session import START_METHOD_LAUNCH, START_METHOD_CMDLINE
@pytest.mark.parametrize('run_as', ['file', 'module', 'code'])
@pytest.mark.parametrize('start_method', [START_METHOD_LAUNCH, START_METHOD_CMDLINE])
def test_run(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
import os
import sys
import backchannel
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
print('begin')
assert backchannel.read_json() == 'continue'

View file

@ -18,6 +18,8 @@ from pytests.helpers.session import START_METHOD_LAUNCH, START_METHOD_CMDLINE
def test_break_on_entry(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
print('one')
print('two')
print('three')
@ -56,13 +58,15 @@ def test_break_on_entry(debug_session, pyfile, run_as, start_method):
def test_wait_on_normal_exit_enabled(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
print('one')
print('two')
print('three')
debug_session.debug_options += ['WaitOnNormalExit']
bp_line = 3
bp_line = 5
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])
@ -99,6 +103,8 @@ def test_wait_on_abnormal_exit_enabled(debug_session, pyfile, run_as, start_meth
@pyfile
def code_to_debug():
import sys
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
print('one')
print('two')
print('three')
@ -106,7 +112,7 @@ def test_wait_on_abnormal_exit_enabled(debug_session, pyfile, run_as, start_meth
debug_session.debug_options += ['WaitOnAbnormalExit']
bp_line = 5
bp_line = 7
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])
@ -140,13 +146,15 @@ def test_wait_on_abnormal_exit_enabled(debug_session, pyfile, run_as, start_meth
def test_exit_normally_with_wait_on_abnormal_exit_enabled(debug_session, pyfile, run_as, start_method):
@pyfile
def code_to_debug():
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
print('one')
print('two')
print('three')
debug_session.debug_options += ['WaitOnAbnormalExit']
bp_line = 3
bp_line = 5
bp_file = code_to_debug
debug_session.initialize(target=(run_as, bp_file), start_method=start_method)
debug_session.set_breakpoints(bp_file, [bp_line])

View file

@ -1,3 +1,5 @@
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
print('one')
print('two')
print('three')
print('three')

View file

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
import sys
from dbgimporter import import_and_enable_debugger
import_and_enable_debugger()
def ಏನದರ_ಮ():
print('ಏನೋ ಮಾಡಿದೆ'.encode(sys.stdout.encoding, errors='replace'))
ಏನದರ_ಮ()

View file

@ -0,0 +1,9 @@
import os
def import_and_enable_debugger():
if os.getenv('PTVSD_ENABLE_ATTACH', False):
import ptvsd
host = os.getenv('PTVSD_TEST_HOST', 'localhost')
port = os.getenv('PTVSD_TEST_PORT', '5678')
ptvsd.enable_attach((host, port))
ptvsd.wait_for_attach()

View file

@ -31,6 +31,9 @@ START_METHOD_LAUNCH = ('launch',)
START_METHOD_CMDLINE = ('attach', 'socket', 'cmdline')
START_METHOD_IMPORT = ('attach', 'socket', 'import')
START_METHOD_PID = ('attach', 'pid')
PTVSD_ENABLE_KEY = 'PTVSD_ENABLE_ATTACH'
PTVSD_HOST_KEY = 'PTVSD_TEST_HOST'
PTVSD_PORT_KEY = 'PTVSD_TEST_PORT'
class DebugSession(object):
@ -128,33 +131,33 @@ class DebugSession(object):
self._wait_for_remaining_output()
def prepare_to_run(self):
"""Spawns ptvsd using the configured method, telling it to execute the
provided Python file, module, or code, and establishes a message channel
to it.
If use_backchannel is True, calls self.setup_backchannel() before returning.
If perform_handshake is True, calls self.handshake() before returning.
"""
def _get_argv_for_attach_using_import(self):
argv = [sys.executable]
if self.start_method != ('attach', 'pid'):
argv += [ptvsd.__main__.__file__]
return argv
if self.start_method == ('attach', 'socket', 'cmdline'):
argv += ['--wait']
else:
self._listen()
argv += ['--client']
def _get_argv_for_launch(self):
argv = [sys.executable]
argv += [ptvsd.__main__.__file__]
argv += ['--client']
argv += ['--host', 'localhost', '--port', str(self.ptvsd_port)]
return argv
if self.multiprocess and 'Multiprocess' not in self.debug_options:
self.debug_options += ['Multiprocess']
def _get_argv_for_attach_using_cmdline(self):
argv = [sys.executable]
argv += [ptvsd.__main__.__file__]
argv += ['--wait']
argv += ['--host', 'localhost', '--port', str(self.ptvsd_port)]
return argv
if self.multiprocess_port_range:
argv += ['--multiprocess-port-range', '%d-%d' % self.multiprocess_port_range]
def _get_argv_for_attach_using_pid(self):
argv = [sys.executable]
argv += [ptvsd.__main__.__file__]
argv += ['--host', 'localhost', '--port', str(self.ptvsd_port)]
argv += ['--pid', str(self.pid)]
return argv
def _get_target(self):
argv = []
run_as, path_or_code = self.target
if run_as == 'file':
assert os.path.isfile(path_or_code)
@ -178,10 +181,45 @@ class DebugSession(object):
argv += ['-c', path_or_code]
else:
pytest.fail()
return argv
def prepare_to_run(self):
"""Spawns ptvsd using the configured method, telling it to execute the
provided Python file, module, or code, and establishes a message channel
to it.
If use_backchannel is True, calls self.setup_backchannel() before returning.
If perform_handshake is True, calls self.handshake() before returning.
"""
print('Preparing debug session with method %r' % str(self.start_method))
argv = []
if self.start_method == START_METHOD_LAUNCH:
self._listen()
argv += self._get_argv_for_launch()
elif self.start_method == START_METHOD_CMDLINE:
argv += self._get_argv_for_attach_using_cmdline()
elif self.start_method == START_METHOD_IMPORT:
argv += self._get_argv_for_attach_using_import()
# TODO: Remove adding ot python path after enabling TOX
ptvsd_path = os.path.dirname(os.path.dirname(ptvsd.__main__.__file__))
self.env['PYTHONPATH'] = ptvsd_path + os.pathsep + self.env['PYTHONPATH']
self.env[PTVSD_ENABLE_KEY] = '1'
self.env[PTVSD_HOST_KEY] = 'localhost'
self.env[PTVSD_PORT_KEY] = str(self.ptvsd_port)
elif self.start_method == START_METHOD_PID:
argv += self._get_argv_for_attach_using_pid()
else:
pytest.fail()
argv += self._get_target()
if self.program_args:
argv += list(self.program_args)
if self.multiprocess and 'Multiprocess' not in self.debug_options:
self.debug_options += ['Multiprocess']
if self.use_backchannel:
self.setup_backchannel()
if self.backchannel_port:
@ -190,6 +228,7 @@ class DebugSession(object):
print('Current directory: %s' % os.getcwd())
print('PYTHONPATH: %s' % self.env['PYTHONPATH'])
print('Spawning %r' % argv)
self.process = subprocess.Popen(argv, env=self.env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=self.cwd)
self.pid = self.process.pid
self.psutil_process = psutil.Process(self.pid)
@ -199,7 +238,7 @@ class DebugSession(object):
self._capture_output(self.process.stdout, 'OUT')
self._capture_output(self.process.stderr, 'ERR')
if self.start_method == ('attach', 'socket', 'cmdline'):
if self.start_method != START_METHOD_LAUNCH:
self.connect()
self.connected.wait()
assert self.ptvsd_port