def test_subprocess(debug_session, pyfile, start_method, run_as): @pyfile def child(): import sys import backchannel from dbgimporter import import_and_enable_debugger import_and_enable_debugger() backchannel.write_json(sys.argv) @pyfile def parent(): 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) process.wait() debug_session.program_args += [child] debug_session.initialize(multiprocess=True, target=(run_as, parent), start_method=start_method, use_backchannel=True) debug_session.start_debugging() root_start_request, = debug_session.all_occurrences_of(Request('launch') | Request('attach')) root_process, = debug_session.all_occurrences_of(Event('process')) root_pid = int(root_process.body['systemProcessId']) child_subprocess = debug_session.wait_for_next(Event('ptvsd_subprocess')) assert child_subprocess == Event('ptvsd_subprocess', { 'rootProcessId': root_pid, 'parentProcessId': root_pid, 'processId': ANY.int, 'port': ANY.int, 'rootStartRequest': { 'seq': ANY.int, 'type': 'request', 'command': root_start_request.command, 'arguments': root_start_request.arguments, } }) child_pid = child_subprocess.body['processId'] child_port = child_subprocess.body['port'] debug_session.proceed() child_session = DebugSession(start_method=START_METHOD_CMDLINE, ptvsd_port=child_port, pid=child_pid) child_session.ignore_unobserved = debug_session.ignore_unobserved child_session.connect() child_session.handshake() child_session.start_debugging() child_argv = debug_session.read_json() assert child_argv == [child, '--arg1', '--arg2', '--arg3'] child_session.wait_for_exit() debug_session.wait_for_exit()
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 @pyfile def parent(): import backchannel 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) backchannel.read_json() debug_session.program_args += [child] debug_session.initialize(multiprocess=True, target=(run_as, parent), start_method=start_method, use_backchannel=True) debug_session.start_debugging() child_subprocess = debug_session.wait_for_next(Event('ptvsd_subprocess')) child_pid = child_subprocess.body['processId'] child_port = child_subprocess.body['port'] debug_session.proceed() child_session = DebugSession(start_method=START_METHOD_CMDLINE, ptvsd_port=child_port, pid=child_pid) child_session.expected_returncode = ANY child_session.connect() child_session.handshake() child_session.start_debugging() if debug_session.start_method == START_METHOD_LAUNCH: # In launch scenario, terminate the parent process by disconnecting from it. debug_session.expected_returncode = ANY disconnect = debug_session.send_request('disconnect', {}) debug_session.wait_for_next(Response(disconnect)) else: # In attach scenario, just let the parent process run to completion. debug_session.expected_returncode = 0 debug_session.write_json(None) debug_session.wait_for_exit() child_session.wait_for_exit()