def expectation_of(message): if isinstance(message, messaging.Event): return Event(some.str.equal_to(message.event), some.dict.equal_to(message.body)) elif isinstance(message, messaging.Request): return Request(some.str.equal_to(message.command), some.dict.equal_to(message.arguments)) else: raise AssertionError("Unsupported message type")
def __setitem__(self, key, value): """Sets debug_me.scratchpad[key] = value inside the debugged process. """ stackTrace_responses = self.session.all_occurrences_of( Response(Request("stackTrace"))) assert ( stackTrace_responses ), 'scratchpad requires at least one "stackTrace" request in the timeline.' stack_trace = stackTrace_responses[-1].body frame_id = stack_trace["stackFrames"][0]["id"] log.info("{0} debug_me.scratchpad[{1!r}] = {2!r}", self.session, key, value) expr = fmt("__import__('debug_me').scratchpad[{0!r}] = {1!r}", key, value) self.session.request("evaluate", { "frameId": frame_id, "context": "repl", "expression": expr })
def test_multiprocessing(pyfile, start_method, run_as): @pyfile def code_to_debug(): import multiprocessing import platform import sys import debug_me # noqa def child_of_child(q): print("entering child of child") assert q.get() == 2 q.put(3) print("leaving child of child") def child(q): print("entering child") assert q.get() == 1 print("spawning child of child") p = multiprocessing.Process(target=child_of_child, args=(q, )) p.start() p.join() assert q.get() == 3 q.put(4) print("leaving child") if __name__ == "__main__": from debug_me import backchannel if sys.version_info >= (3, 4): multiprocessing.set_start_method("spawn") else: assert platform.system() == "Windows" print("spawning child") q = multiprocessing.Queue() p = multiprocessing.Process(target=child, args=(q, )) p.start() print("child spawned") backchannel.send(p.pid) q.put(1) assert backchannel.receive() == "continue" q.put(2) p.join() assert q.get() == 4 q.close() backchannel.send("done") with debug.Session(start_method) as parent_session: parent_backchannel = parent_session.setup_backchannel() parent_session.debug_options |= {"Multiprocess"} parent_session.configure(run_as, code_to_debug) parent_session.start_debugging() root_start_request, = parent_session.all_occurrences_of( Request("launch") | Request("attach")) root_process, = parent_session.all_occurrences_of(Event("process")) root_pid = int(root_process.body["systemProcessId"]) child_pid = parent_backchannel.receive() child_subprocess = parent_session.wait_for_next( Event("ptvsd_subprocess")) assert child_subprocess == Event( "ptvsd_subprocess", { "rootProcessId": root_pid, "parentProcessId": root_pid, "processId": child_pid, "port": some.int, "rootStartRequest": { "seq": some.int, "type": "request", "command": root_start_request.command, "arguments": root_start_request.arguments, }, }, ) parent_session.proceed() with parent_session.attach_to_subprocess( child_subprocess) as child_session: child_session.start_debugging() grandchild_subprocess = parent_session.wait_for_next( Event("ptvsd_subprocess")) assert grandchild_subprocess == Event( "ptvsd_subprocess", { "rootProcessId": root_pid, "parentProcessId": child_pid, "processId": some.int, "port": some.int, "rootStartRequest": { "seq": some.int, "type": "request", "command": root_start_request.command, "arguments": root_start_request.arguments, }, }, ) parent_session.proceed() with parent_session.attach_to_subprocess( grandchild_subprocess) as grandchild_session: grandchild_session.start_debugging() parent_backchannel.send("continue") assert parent_backchannel.receive() == "done"
def test_subprocess(pyfile, start_method, run_as): @pyfile def child(): import sys from debug_me import backchannel backchannel.send(sys.argv) @pyfile def parent(): import os import subprocess import sys import debug_me # noqa 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() with debug.Session(start_method, backchannel=True) as parent_session: parent_backchannel = parent_session.backchannel parent_session.configure(run_as, parent, subProcess=True, args=[child]) parent_session.start_debugging() root_start_request, = parent_session.all_occurrences_of( Request("launch") | Request("attach")) root_process, = parent_session.all_occurrences_of(Event("process")) root_pid = int(root_process.body["systemProcessId"]) child_subprocess = parent_session.wait_for_next( Event("ptvsd_subprocess")) assert child_subprocess == Event( "ptvsd_subprocess", { "rootProcessId": root_pid, "parentProcessId": root_pid, "processId": some.int, "port": some.int, "rootStartRequest": { "seq": some.int, "type": "request", "command": root_start_request.command, "arguments": root_start_request.arguments, }, }, ) parent_session.proceed() with parent_session.attach_to_subprocess( child_subprocess) as child_session: child_session.start_debugging() child_argv = parent_backchannel.receive() assert child_argv == [child, "--arg1", "--arg2", "--arg3"]
def test_request_response(make_timeline, outcome): timeline, initial_history = make_timeline() messages = MessageFactory() request_msg = messages.request("next", {"threadId": 3}) request_exp = expectation_of(request_msg) request = timeline.record_request(request_msg) assert request == request_exp assert request.command == request_msg.command assert request.arguments == request_msg.arguments assert request.circumstances == ( "request", request_msg.command, request_msg.arguments, ) with timeline.frozen(): assert timeline.last is request assert timeline.history( ) == initial_history + [some.object.same_as(request)] timeline.expect_realized(request_exp) timeline.expect_realized(Request("next")) response_msg = messages.response( request_msg, {} if outcome == "success" else Exception("error!")) response = timeline.record_response(request, response_msg) assert response.request is request assert response.body == response_msg.body if outcome == "success": assert response.success else: assert not response.success assert response.circumstances == ("response", request, response_msg.body) assert response == Response(request, response_msg.body) assert response == Response(request, some.object) assert response == Response(request) if outcome == "success": assert response == Response(request, some.dict) assert response != Response(request, some.error) else: assert response != Response(request, some.dict) assert response == Response(request, some.error) assert response == Response(request_exp, response_msg.body) assert response == Response(request_exp, some.object) assert response == Response(request_exp) if outcome == "success": assert response == Response(request_exp, some.dict) assert response != Response(request_exp, some.error) else: assert response != Response(request_exp, some.dict) assert response == Response(request_exp, some.error) with timeline.frozen(): assert timeline.last is response assert timeline.history() == initial_history + [ some.object.same_as(request), some.object.same_as(response), ] timeline.expect_realized(Response(request)) timeline.expect_realized(Response(request, response_msg.body)) timeline.expect_realized(Response(request, some.object)) if outcome == "success": timeline.expect_realized(Response(request, some.dict)) timeline.expect_not_realized(Response(request, some.error)) else: timeline.expect_not_realized(Response(request, some.dict)) timeline.expect_realized(Response(request, some.error)) timeline.expect_realized(Response(request)) timeline.expect_realized(Response(request_exp, response_msg.body)) timeline.expect_realized(Response(request_exp, some.object)) if outcome == "success": timeline.expect_realized(Response(request_exp, some.dict)) timeline.expect_not_realized(Response(request_exp, some.error)) else: timeline.expect_not_realized(Response(request_exp, some.dict)) timeline.expect_realized(Response(request_exp, some.error))