def test_debugger_core_step_out(debugger_api, run_robot_cli) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint debugger_impl = install_robot_debugger() target = debugger_api.get_dap_case_file("case_step_out.robot") line = debugger_api.get_line_index_with_content("Break 1", target) debugger_impl.set_breakpoints(target, RobotBreakpoint(line)) busy_wait = DummyBusyWait(debugger_impl) debugger_impl.busy_wait = busy_wait busy_wait.on_wait = [debugger_impl.step_out, debugger_impl.step_continue] code = run_robot_cli(target) assert busy_wait.waited == 2 assert busy_wait.proceeded == 2 assert len(busy_wait.stack) == 2 assert [x.name for x in busy_wait.stack[0]] == [ "Should Be Equal", "My Equal Redefined", "TestCase: Can use resource keywords", "TestSuite: Case Step Out", ] assert [x.name for x in busy_wait.stack[1]] == [ "Yet Another Equal Redefined", "TestCase: Can use resource keywords", "TestSuite: Case Step Out", ] assert code == 0
def test_debugger_core_with_setup_teardown(debugger_api, run_robot_cli, data_regression) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint debugger_impl = install_robot_debugger() target = debugger_api.get_dap_case_file("case_setup_teardown.robot") debugger_impl.set_breakpoints( target, ( RobotBreakpoint( debugger_api.get_line_index_with_content( "Suite Setup", target)), RobotBreakpoint( debugger_api.get_line_index_with_content( "Suite Teardown", target)), ), ) busy_wait = DummyBusyWait(debugger_impl) debugger_impl.busy_wait = busy_wait busy_wait.on_wait = [ debugger_impl.step_continue, debugger_impl.step_continue ] code = run_robot_cli(target) assert busy_wait.waited == 2 assert busy_wait.proceeded == 2 assert len(busy_wait.stack) == 2 data_regression.check(stack_frames_repr(busy_wait.stack)) assert code == 0
def test_debugger_core_if(debugger_api, robot_thread, data_regression) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint from robotframework_debug_adapter.constants import MAIN_THREAD_ID debugger_impl = install_robot_debugger() target = debugger_api.get_dap_case_file( "case_control_flow/case_control_flow_if.robot") line = debugger_api.get_line_index_with_content("Break 1", target) debugger_impl.set_breakpoints(target, RobotBreakpoint(line)) robot_thread.run_target(target) stack_lst: List[Optional[List[StackFrame]]] = [] try: dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 1) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 2) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) finally: debugger_impl.step_in() # Will actually finish the program now. dbg_wait_for(lambda: debugger_impl.busy_wait.proceeded == 2) data_regression.check(stack_frames_repr(stack_lst)) dbg_wait_for(lambda: robot_thread.result_code == 0)
def test_debugger_core_hit_condition_breakpoint(debugger_api, robot_thread) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint debugger_impl = install_robot_debugger() target = debugger_api.get_dap_case_file("case_condition.robot") line = debugger_api.get_line_index_with_content("Log ${counter}", target) debugger_impl.set_breakpoints(target, RobotBreakpoint(line, hit_condition=2)) robot_thread.run_target(target) # It should only stop once (when counter == 2). dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 1) thread_id = debugger_impl.get_current_thread_id(robot_thread) frame_ids = list(debugger_impl.iter_frame_ids(thread_id)) eval_info = debugger_impl.evaluate(frame_ids[0], "${counter}") assert eval_info.future.result() == 2 debugger_impl.step_continue() dbg_wait_for(lambda: robot_thread.result_code == 0)
def __init__(self, s, debug): threading.Thread.__init__(self) self.daemon = True self._debug = debug self._socket = s self._write_queue = queue.Queue() self.configuration_done = threading.Event() self.terminated = threading.Event() log = get_log() if debug: log.debug("Patching execution context...") from robotframework_debug_adapter.debugger_impl import ( install_robot_debugger, ) try: import robot except ImportError: # If unable to import robot, don't error here (proceed as if # it was without debugging -- it should fail later on when # about to run the code, at which point the actual DAP is # in place). self._debugger_impl = None else: debugger_impl = install_robot_debugger() debugger_impl.busy_wait.before_wait.append( self._notify_stopped) log.debug("Finished patching execution context.") self._debugger_impl = debugger_impl else: self._debugger_impl = None
def test_debugger_core_evaluate(debugger_api_core, robot_thread, tmpdir) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint from robotframework_debug_adapter.constants import MAIN_THREAD_ID from robotframework_debug_adapter.debugger_impl import InvalidFrameIdError from robotframework_debug_adapter.debugger_impl import InvalidFrameTypeError debugger_impl = install_robot_debugger() target = debugger_api_core.get_dap_case_file("case_evaluate.robot") debugger_api_core.target = target line = debugger_api_core.get_line_index_with_content("Break 1") debugger_impl.set_breakpoints(target, RobotBreakpoint(line)) robot_thread.run_target(target) dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 1) try: invalid_frame_id = -11 filename = str(tmpdir.join("file.txt")) filename = filename.replace("\\", "/") content = "file.txt" frame_ids = list(debugger_impl.iter_frame_ids(MAIN_THREAD_ID)) # Fail due to invalid frame id eval_info = debugger_impl.evaluate( invalid_frame_id, "Create File %s content=%s" % (filename, content)) with pytest.raises(InvalidFrameIdError): eval_info.future.result() # Fail because the stack selected is not a keyword stack. eval_info = debugger_impl.evaluate( frame_ids[-1], "Create File %s content=%s" % (filename, content)) with pytest.raises(InvalidFrameTypeError): eval_info.future.result() # Keyword evaluation works eval_info = debugger_impl.evaluate( frame_ids[0], "Create File %s content=%s" % (filename, content)) assert eval_info.future.result() is None with open(filename, "r") as stream: contents = stream.read() assert contents == content # Get variable in evaluation works eval_info = debugger_impl.evaluate(frame_ids[0], "${arg1}") assert eval_info.future.result() == "2" eval_info = debugger_impl.evaluate(frame_ids[0], "${ARG1}") assert eval_info.future.result() == "2" finally: debugger_impl.step_continue()
def test_debugger_core_for(debugger_api, robot_thread, data_regression) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint from robotframework_debug_adapter.constants import MAIN_THREAD_ID debugger_impl = install_robot_debugger() target = debugger_api.get_dap_case_file( "case_control_flow/case_control_flow_for.robot") line = debugger_api.get_line_index_with_content("Break 1", target) debugger_impl.set_breakpoints(target, RobotBreakpoint(line)) robot_thread.run_target(target) stack_lst: List[Optional[List[StackFrame]]] = [] try: dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 1) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 2) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 3) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 4) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) n_proceeded = 4 if IS_ROBOT_4_ONWARDS: # We have additional steps as we get one step with the creation # of the ${counter} variable when stepping into the for. debugger_impl.step_in() dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 5) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 6) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) n_proceeded = 6 finally: debugger_impl.step_continue() dbg_wait_for(lambda: debugger_impl.busy_wait.proceeded == n_proceeded) if IS_ROBOT_4_ONWARDS: basename = "test_debugger_core_for.v4" else: basename = "test_debugger_core_for.v3" data_regression.check(stack_frames_repr(stack_lst), basename=basename) dbg_wait_for(lambda: robot_thread.result_code == 0)
def test_debugger_core_keyword_if(debugger_api, robot_thread, data_regression) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint from robotframework_debug_adapter.constants import MAIN_THREAD_ID debugger_impl = install_robot_debugger() target = debugger_api.get_dap_case_file( "case_control_flow/case_control_flow_for.robot") line = debugger_api.get_line_index_with_content("Break 2", target) debugger_impl.set_breakpoints(target, RobotBreakpoint(line)) robot_thread.run_target(target) stack_lst = [] def check_waited(expected): def msg(): return "Expected waited to be: %s. Found: %s" % ( expected, debugger_impl.busy_wait.waited, ) dbg_wait_for(lambda: debugger_impl.busy_wait.waited == expected, msg=msg) try: check_waited(1) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() check_waited(2) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() check_waited(3) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) debugger_impl.step_in() check_waited(4) stack_lst.append(debugger_impl.get_frames(MAIN_THREAD_ID)) finally: debugger_impl.step_continue() dbg_wait_for(lambda: debugger_impl.busy_wait.proceeded == 4) data_regression.check(stack_frames_repr(stack_lst)) dbg_wait_for(lambda: robot_thread.result_code == 0)
def __init__(self, socket, debug: bool): """ :param socket: :param debug: True means that we should run in debug mode and False means that the --nodebug flag was passed. """ threading.Thread.__init__(self) self.daemon = True self._socket = socket self._write_queue = queue.Queue() self.configuration_done = threading.Event() self.terminated = threading.Event() self._run_in_debug_mode = debug log = get_log() if debug: log.debug("Patching execution context...") from robotframework_debug_adapter.debugger_impl import ( install_robot_debugger, ) try: import robot except ImportError: log.info( "Unable to import Robot (debug will not be available).") # If unable to import robot, don't error here (proceed as if # it was without debugging -- it should fail later on when # about to run the code, at which point the actual DAP is # in place). self._debugger_impl = None else: debugger_impl = install_robot_debugger() debugger_impl.busy_wait.before_wait.append( self._notify_stopped) debugger_impl.write_message = self.write_message log.debug("Finished patching execution context.") self._debugger_impl = debugger_impl else: self._debugger_impl = None
def test_debugger_core(debugger_api_core, robot_thread) -> None: from robotframework_debug_adapter.debugger_impl import install_robot_debugger from robotframework_debug_adapter.debugger_impl import RobotBreakpoint debugger_impl = install_robot_debugger() target = debugger_api_core.get_dap_case_file("case_log.robot") debugger_api_core.target = target line = debugger_api_core.get_line_index_with_content( "check that log works") debugger_impl.set_breakpoints(target, RobotBreakpoint(line)) robot_thread.run_target(target) thread_id = debugger_impl.get_current_thread_id(robot_thread) try: dbg_wait_for(lambda: debugger_impl.busy_wait.waited == 1) stack = debugger_impl.get_frames(thread_id) finally: debugger_impl.step_continue() dbg_wait_for(lambda: debugger_impl.busy_wait.proceeded == 1) assert stack and len(stack) == 3 dbg_wait_for(lambda: robot_thread.result_code == 0)