예제 #1
0
def test_vsc_exception_options_raise_with_except(pyfile, run_as, start_method, raised, uncaught):

    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def raise_with_except():
            try:
                raise ArithmeticError('bad code')  # @exception_line
            except Exception:
                pass

        raise_with_except()

    line_numbers = get_marked_line_numbers(code_to_debug)
    ex_line = line_numbers['exception_line']
    filters = []
    filters += ['raised'] if raised == 'raisedOn' else []
    filters += ['uncaught'] if uncaught == 'uncaughtOn' else []
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
        )
        session.send_request('setExceptionBreakpoints', {
            'filters': filters
        }).wait_for_response()
        session.start_debugging()

        expected = ANY.dict_with({
            'exceptionId': ANY.such_that(lambda s: s.endswith('ArithmeticError')),
            'description': 'bad code',
            'breakMode': 'always' if raised == 'raisedOn' else 'unhandled',
            'details': ANY.dict_with({
                'typeName': ANY.such_that(lambda s: s.endswith('ArithmeticError')),
                'message': 'bad code',
                'source': Path(code_to_debug),
            }),
        })

        if raised == 'raisedOn':
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert ex_line == frames[0]['line']

            resp_exc_info = session.send_request('exceptionInfo', {
                'threadId': hit.thread_id
            }).wait_for_response()

            assert resp_exc_info.body == expected
            session.send_request('continue').wait_for_response(freeze=False)

        # uncaught should not 'stop' matter since the exception is caught

        session.wait_for_exit()
예제 #2
0
def test_justmycode_frames(pyfile, run_as, start_method, jmc):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        print('break here')  #@bp

    line_numbers = get_marked_line_numbers(code_to_debug)
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
            debug_options=[] if jmc == 'jmcOn' else ['DebugStdLib'])

        bp_line = line_numbers['bp']

        actual_bps = session.set_breakpoints(code_to_debug, [bp_line])
        actual_bps = [bp['line'] for bp in actual_bps]
        session.start_debugging()

        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert frames[0] == ANY.dict_with({
            'line':
            bp_line,
            'source':
            ANY.dict_with({'path': Path(code_to_debug)})
        })

        if jmc == 'jmcOn':
            assert len(frames) == 1
            session.send_request('stepIn', {
                'threadId': hit.thread_id
            }).wait_for_response()
            # 'step' should terminate the debuggee
        else:
            assert len(frames) >= 1
            session.send_request('stepIn', {
                'threadId': hit.thread_id
            }).wait_for_response()

            # 'step' should enter stdlib
            hit2 = session.wait_for_thread_stopped()
            frames2 = hit2.stacktrace.body['stackFrames']
            assert frames2[0]['source']['path'] != Path(code_to_debug)

            # 'continue' should terminate the debuggee
            session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
예제 #3
0
def test_set_variable(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        import backchannel
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        import ptvsd
        a = 1
        ptvsd.break_into_debugger()
        backchannel.write_json(a)

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
            use_backchannel=True,
        )
        session.start_debugging()
        hit = session.wait_for_thread_stopped()

        resp_scopes = session.send_request('scopes',
                                           arguments={
                                               'frameId': hit.frame_id
                                           }).wait_for_response()
        scopes = resp_scopes.body['scopes']
        assert len(scopes) > 0

        resp_variables = session.send_request(
            'variables',
            arguments={
                'variablesReference': scopes[0]['variablesReference']
            }).wait_for_response()
        variables = list(v for v in resp_variables.body['variables']
                         if v['name'] == 'a')
        assert len(variables) == 1
        assert variables[0] == {
            'type': 'int',
            'value': '1',
            'name': 'a',
            'evaluateName': "a"
        }

        resp_set_variable = session.send_request(
            'setVariable',
            arguments={
                'variablesReference': scopes[0]['variablesReference'],
                'name': 'a',
                'value': '1000'
            }).wait_for_response()
        assert resp_set_variable.body == ANY.dict_with({
            'type': 'int',
            'value': '1000'
        })

        session.send_request('continue').wait_for_response(freeze=False)

        assert session.read_json() == 1000

        session.wait_for_exit()
예제 #4
0
    def test_add_multi_thread(self):
        sink = ModulesEventSink()
        self.mgr = ModulesManager(sink)

        orig_module = sys.modules['ptvsd.untangle']
        expected_module = ANY.dict_with({
            'id': ANY.int,
            'name': orig_module.__name__,
            'package': orig_module.__package__,
            'path': orig_module.__file__,
            'version': orig_module.__version__,
        })
        self.path = orig_module.__file__

        def thread_worker(test, expected):
            time.sleep(0.01)
            assert expected_module == test.mgr.add_or_get_from_path(test.path)

        threads = []
        for _ in range(10):
            thread = threading.Thread(target=thread_worker,
                                      args=(self, expected_module))
            threads.append(thread)
            thread.start()

        for thread in threads:
            thread.join()

        assert 1 == len(sink.event_data)
        assert [expected_module] == self.mgr.get_all()
예제 #5
0
def test_attaching_by_pid_no_threading(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        # import_and_enable_debugger
        import time

        wait = True
        i = 0
        while wait:
            i += 1
            print('in loop')
            time.sleep(0.1)
            if i > 100:
                raise AssertionError(
                    'Debugger did not change wait to False as expected within the timeout.'
                )

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        session.start_debugging()
        # Wait for the first print to make sure we're in the proper state to pause.
        session.wait_for_next(
            Event('output',
                  ANY.dict_with({
                      'category': 'stdout',
                      'output': 'in loop'
                  })))
        _change_wait_to_false_and_exit(session)
예제 #6
0
def test_attaching_by_pid(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        # import_and_enable_debugger()
        import time
        def do_something(i):
            time.sleep(0.1)
            print(i)
        for i in range(100):
            do_something(i)
    bp_line = 5
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        session.set_breakpoints(code_to_debug, [bp_line])
        session.start_debugging()
        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert bp_line == frames[0]['line']

        # remove breakpoint and continue
        session.set_breakpoints(code_to_debug, [])
        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_next(Event('output', ANY.dict_with({'category': 'stdout'})))
        session.wait_for_exit()
예제 #7
0
    def test_valid_new_module(self):
        sink = ModulesEventSink()
        mgr = ModulesManager(sink)

        orig_module = sys.modules['ptvsd.untangle']
        expected_module = ANY.dict_with({
            'id': ANY.int,
            'name': orig_module.__name__,
            'package': orig_module.__package__,
            'path': orig_module.__file__,
            'version': orig_module.__version__,
        })

        assert expected_module == mgr.add_or_get_from_path(
            ptvsd.untangle.__file__)
        assert 1 == len(sink.event_data)
        assert [expected_module] == mgr.get_all()
        assert sink.event_data == [
            {
                'event': 'module',
                'args': {
                    'reason': 'new',
                    'module': expected_module,
                },
            },
        ]
예제 #8
0
def test_with_tab_in_output(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        a = '\t'.join(('Hello', 'World'))
        print(a)
        # Break here so we are sure to get the output event.
        a = 1 # @bp1

    line_numbers = get_marked_line_numbers(code_to_debug)
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )

        session.set_breakpoints(code_to_debug, [line_numbers['bp1']])
        session.start_debugging()

        # Breakpoint at the end just to make sure we get all output events.
        session.wait_for_thread_stopped()
        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()

        output = session.all_occurrences_of(Event('output', ANY.dict_with({'category': 'stdout'})))
        output_str = ''.join(o.body['output'] for o in output)
        assert output_str.startswith('Hello\tWorld')
예제 #9
0
def test_redirect_output(pyfile, run_as, start_method, redirect):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        for i in [111, 222, 333, 444]:
            print(i)

        print()  # @bp1

    line_numbers = get_marked_line_numbers(code_to_debug)
    with DebugSession() as session:
        # By default 'RedirectOutput' is always set. So using this way
        #  to override the default in session.
        session.debug_options = [redirect] if bool(redirect) else []
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )

        session.set_breakpoints(code_to_debug, [line_numbers['bp1']])
        session.start_debugging()

        # Breakpoint at the end just to make sure we get all output events.
        session.wait_for_thread_stopped()
        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()

        output = session.all_occurrences_of(
            Event('output', ANY.dict_with({'category': 'stdout'})))
        expected = ['111', '222', '333', '444'] if bool(redirect) else []
        assert expected == list(o.body['output'] for o in output
                                if len(o.body['output']) == 3)
예제 #10
0
def test_nodebug(pyfile, run_as):
    @pyfile
    def code_to_debug():
        # import_and_enable_debugger
        import backchannel
        backchannel.read_json()
        print('ok')

    with DebugSession() as session:
        session.no_debug = True
        session.initialize(target=(run_as, code_to_debug),
                           start_method='launch',
                           use_backchannel=True)
        session.set_breakpoints(code_to_debug, [3])
        session.start_debugging()

        session.write_json(None)

        # Breakpoint shouldn't be hit.
        session.wait_for_exit()

        session.expect_realized(
            Event('output',
                  ANY.dict_with({
                      'category': 'stdout',
                      'output': 'ok',
                  })))
예제 #11
0
def test_flask_template_exception_no_multiproc(start_method):
    with DebugSession() as session:
        _initialize_flask_session_no_multiproc(session, start_method)

        session.send_request('setExceptionBreakpoints', arguments={
            'filters': ['raised', 'uncaught'],
        }).wait_for_response()

        session.start_debugging()

        # wait for Flask web server to start
        wait_for_connection(FLASK_PORT)
        base_link = FLASK_LINK
        part = 'badtemplate'
        link = base_link + part if base_link.endswith('/') else ('/' + part)
        web_request = get_web_content(link, {})

        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert frames[0] == ANY.dict_with({
            'id': ANY.dap_id,
            'name': 'template' if sys.version_info[0] >= 3 else 'Jinja2 TemplateSyntaxError',
            'source': ANY.dict_with({
                'sourceReference': ANY.dap_id,
                'path': Path(FLASK1_BAD_TEMPLATE),
            }),
            'line': 8,
            'column': 1,
        })

        resp_exception_info = session.send_request(
            'exceptionInfo',
            arguments={'threadId': hit.thread_id, }
        ).wait_for_response()
        exception = resp_exception_info.body
        assert exception == ANY.dict_with({
            'exceptionId': ANY.such_that(lambda s: s.endswith('TemplateSyntaxError')),
            'breakMode': 'always',
            'description': ANY.such_that(lambda s: s.find('doesnotexist') > -1),
            'details': ANY.dict_with({
                'message': ANY.such_that(lambda s: s.find('doesnotexist') > -1),
                'typeName': ANY.such_that(lambda s: s.endswith('TemplateSyntaxError')),
            })
        })

        session.send_request('continue').wait_for_response(freeze=False)

        # ignore response for exception tests
        web_request.wait_for_response()

        # shutdown to web server
        link = base_link + 'exit' if base_link.endswith('/') else '/exit'
        get_web_content(link).wait_for_response()

        session.wait_for_exit()
예제 #12
0
def test_conditional_breakpoint(pyfile, run_as, start_method, condition_key):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        for i in range(0, 10):
            print(i)

    expected = {
        'condition_var': ('condition', 'i==5', '5', 1),
        'hitCondition_#': ('hitCondition', '5', '4', 1),
        'hitCondition_eq': ('hitCondition', '==5', '4', 1),
        'hitCondition_gt': ('hitCondition', '>5', '5', 5),
        'hitCondition_ge': ('hitCondition', '>=5', '4', 6),
        'hitCondition_lt': ('hitCondition', '<5', '0', 4),
        'hitCondition_le': ('hitCondition', '<=5', '0', 5),
        'hitCondition_mod': ('hitCondition', '%3', '2', 3),
    }
    condition_type, condition, value, hits = expected[condition_key]

    bp_line = 4
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
        )
        session.send_request('setBreakpoints', arguments={
            'source': {'path': code_to_debug},
            'breakpoints': [{'line': bp_line, condition_type: condition}],
        }).wait_for_response()
        session.start_debugging()
        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert bp_line == frames[0]['line']

        resp_scopes = session.send_request('scopes', arguments={
            'frameId': hit.frame_id
        }).wait_for_response()
        scopes = resp_scopes.body['scopes']
        assert len(scopes) > 0

        resp_variables = session.send_request('variables', arguments={
            'variablesReference': scopes[0]['variablesReference']
        }).wait_for_response()
        variables = list(v for v in resp_variables.body['variables']
                         if v['name'] == 'i')
        assert variables == [
            ANY.dict_with({'name': 'i', 'type': 'int', 'value': value, 'evaluateName': 'i'})
        ]

        session.send_request('continue').wait_for_response(freeze=False)
        for i in range(1, hits):
            session.wait_for_thread_stopped()
            session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
예제 #13
0
def test_add_and_remove_breakpoint(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        for i in range(0, 10):
            print(i)
        import backchannel
        backchannel.read_json()

    bp_line = 4
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            use_backchannel=True,
        )
        session.set_breakpoints(code_to_debug, [bp_line])
        session.start_debugging()

        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert bp_line == frames[0]['line']

        # remove breakpoints in file
        session.set_breakpoints(code_to_debug, [])
        session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_next(
            Event('output', ANY.dict_with({
                'category': 'stdout',
                'output': '9'
            })))
        session.write_json('done')
        session.wait_for_exit()

        output = session.all_occurrences_of(
            Event('output', ANY.dict_with({'category': 'stdout'})))
        output = sorted(
            int(o.body['output'].strip()) for o in output
            if len(o.body['output'].strip()) > 0)
        assert list(range(0, 10)) == output
예제 #14
0
def test_completions_scope(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
            def do_someting(self):
                someVariable = self.some_var
                return someVariable
        def someFunction(someVar):
            someVariable = someVar
            return SomeClass(someVariable).do_someting()
        someFunction('value')
        print('done')

    expected = expected_at_line[bp_line]

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('stopped'), Event('continued')],
        )
        session.set_breakpoints(code_to_debug, [bp_line])
        session.start_debugging()

        thread_stopped = session.wait_for_next(Event('stopped', ANY.dict_with({'reason': 'breakpoint'})))
        assert thread_stopped.body['threadId'] is not None
        tid = thread_stopped.body['threadId']

        resp_stacktrace = session.send_request('stackTrace', arguments={
            'threadId': tid,
        }).wait_for_response()
        assert resp_stacktrace.body['totalFrames'] > 0
        frames = resp_stacktrace.body['stackFrames']
        assert len(frames) > 0

        fid = frames[0]['id']
        resp_completions = session.send_request('completions', arguments={
            'text': 'some',
            'frameId': fid,
            'column': 5,
        }).wait_for_response()
        targets = resp_completions.body['targets']

        session.send_request('continue').wait_for_response(freeze=False)

        targets.sort(key=lambda t: t['label'])
        expected.sort(key=lambda t: t['label'])
        assert targets == expected

        session.wait_for_exit()
예제 #15
0
def test_log_point(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        a = 10
        for i in range(1, a):
            print('value: %d' % i)
        # Break at end too so that we're sure we get all output
        # events before the break.
        a = 10

    bp_line = 5
    end_bp_line = 8
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
        )
        session.send_request('setBreakpoints',
                             arguments={
                                 'source': {
                                     'path': code_to_debug
                                 },
                                 'breakpoints': [{
                                     'line': bp_line,
                                     'logMessage': 'log: {a + i}'
                                 }, {
                                     'line': end_bp_line
                                 }],
                             }).wait_for_response()
        session.start_debugging()

        # Breakpoint at the end just to make sure we get all output events.
        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert end_bp_line == frames[0]['line']

        session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
        assert session.get_stderr_as_string() == b''

        output = session.all_occurrences_of(
            Event('output', ANY.dict_with({'category': 'stdout'})))
        output_str = ''.join(o.body['output'] for o in output)
        logged = sorted(
            int(i) for i in re.findall(r"log:\s([0-9]*)", output_str))
        values = sorted(
            int(i) for i in re.findall(r"value:\s([0-9]*)", output_str))

        assert logged == list(range(11, 20))
        assert values == list(range(1, 10))
예제 #16
0
def test_unicode(pyfile, run_as, start_method):
    # On Python 3, variable names can contain Unicode characters.
    # On Python 2, they must be ASCII, but using a Unicode character in an expression should not crash debugger.

    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        import ptvsd
        # Since Unicode variable name is a SyntaxError at parse time in Python 2,
        # this needs to do a roundabout way of setting it to avoid parse issues.
        globals()[u'\u16A0'] = 123
        ptvsd.break_into_debugger()
        print('break')

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
        )
        session.start_debugging()
        hit = session.wait_for_thread_stopped()

        resp_eval = session.send_request('evaluate', arguments={
            'expression': '\u16A0', 'frameId': hit.frame_id,
        }).wait_for_response()

        if sys.version_info >= (3,):
            assert resp_eval.body == ANY.dict_with({
                'type': 'int',
                'result': '123'
            })
        else:
            assert resp_eval.body == ANY.dict_with({
                'type': 'SyntaxError'
            })

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
예제 #17
0
def test_run(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'
        backchannel.write_json(os.path.abspath(sys.modules['ptvsd'].__file__))
        print('end')

    with DebugSession() as session:
        session.initialize(target=(run_as, code_to_debug),
                           start_method=start_method,
                           use_backchannel=True)
        session.start_debugging()
        assert session.timeline.is_frozen

        process_event, = session.all_occurrences_of(Event('process'))
        assert process_event == Event(
            'process',
            ANY.dict_with({
                'name':
                ANY if run_as == 'code' else ANY.such_that(lambda name: (
                    # There can be a difference in file extension (.py/.pyc/.pyo) on clean runs.
                    name == code_to_debug or name == code_to_debug + 'c' or
                    name == code_to_debug + 'o')),
            }))

        session.write_json('continue')
        ptvsd_path = session.read_json()
        expected_ptvsd_path = os.path.abspath(ptvsd.__file__)
        assert (ptvsd_path == expected_ptvsd_path
                or ptvsd_path == expected_ptvsd_path + 'c'
                or ptvsd_path == expected_ptvsd_path + 'o')

        session.wait_for_exit()
예제 #18
0
def test_with_tab_in_output(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        print('Hello\tWorld')

    with DebugSession() as session:
        session.initialize(target=(run_as, code_to_debug),
                           start_method=start_method)
        session.start_debugging()
        session.wait_for_exit()
        output = session.all_occurrences_of(
            Event('output', ANY.dict_with({'category': 'stdout'})))
        output_str = ''.join(o.body['output'] for o in output)
        assert output_str.startswith('Hello\tWorld')
예제 #19
0
def test_run_submodule():
    cwd = get_test_root('testpkgs')
    with DebugSession() as session:
        session.initialize(
            target=('module', 'pkg1.sub'),
            start_method='launch',
            cwd=cwd,
        )
        session.start_debugging()
        session.wait_for_next(
            Event('output',
                  ANY.dict_with({
                      'category': 'stdout',
                      'output': 'three'
                  })))
        session.wait_for_exit()
예제 #20
0
    def test_get_only_module(self):
        sink = ModulesEventSink()
        mgr = ModulesManager(sink)

        expected_module = ANY.dict_with({
            'id': 1,
            'name': 'abc.xyz',
            'package': 'abc',
            'path': '/abc/xyz.py',
            'version': '1.2.3.4a1',
        })

        mgr.path_to_module_id['/abc/xyz.py'] = 1
        mgr.module_id_to_details[1] = expected_module

        assert expected_module == mgr.add_or_get_from_path('/abc/xyz.py')
        assert 0 == len(sink.event_data)
        assert [expected_module] == mgr.get_all()
예제 #21
0
def test_targets(target_kind, client, wait, nodebug, multiproc, extra):
    args = ['--host', 'localhost', '--port', '8888']

    if client:
        args += ['--client']

    if wait:
        args += ['--wait']

    if nodebug:
        args += ['--nodebug']

    if multiproc:
        args += ['--multiprocess']

    if target_kind == 'file':
        target = 'spam.py'
        args += [target]
    elif target_kind == 'module':
        target = 'spam'
        args += ['-m', target]
    elif target_kind == 'code':
        target = '123'
        args += ['-c', target]

    if extra:
        extra = ['ham', '--client', '--wait', '-y', 'spam', '--', '--nodebug', '--host', '--port', '-c', '--something', '-m']
        args += extra
    else:
        extra = []

    print(args)
    reload(ptvsd.options)
    rest = parse(args)
    assert list(rest) == extra
    assert vars(ptvsd.options) == ANY.dict_with({
        'target_kind': target_kind,
        'target': target,
        'host': 'localhost',
        'port': 8888,
        'no_debug': bool(nodebug),
        'wait': bool(wait),
        'multiprocess': bool(multiproc),
    })
예제 #22
0
def test_log_point(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        a = 10
        for i in range(1, a):
            print('value: %d' % i)

    bp_line = 5
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
        )
        session.send_request('setBreakpoints',
                             arguments={
                                 'source': {
                                     'path': code_to_debug
                                 },
                                 'breakpoints': [{
                                     'line': bp_line,
                                     'logMessage': 'log: {a + i}'
                                 }],
                             }).wait_for_response()
        session.start_debugging()

        session.wait_for_exit()
        assert session.get_stderr_as_string() == b''

        output = session.all_occurrences_of(
            Event('output', ANY.dict_with({'category': 'stdout'})))
        output_str = ''.join(o.body['output'] for o in output)
        logged = sorted(
            int(i) for i in re.findall(r"log:\s([0-9]*)", output_str))
        values = sorted(
            int(i) for i in re.findall(r"value:\s([0-9]*)", output_str))

        # NOTE: Due to https://github.com/Microsoft/ptvsd/issues/1028 we may not get
        # all output events. Once that is fixed we should check for the exact output
        # and log value
        assert len(logged) > 0
        assert len(values) > 0
예제 #23
0
def test_run(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'
        backchannel.write_json(os.path.abspath(sys.modules['ptvsd'].__file__))
        print('end')

    with DebugSession() as session:
        session.initialize(target=(run_as, code_to_debug),
                           start_method=start_method,
                           use_backchannel=True)
        session.start_debugging()
        assert session.timeline.is_frozen

        process_event, = session.all_occurrences_of(Event('process'))
        assert process_event == Event(
            'process',
            ANY.dict_with({
                'name':
                '-c' if run_as == 'code' else
                Regex(re.escape(code_to_debug) + r'(c|o)?$')
            }))

        session.write_json('continue')
        ptvsd_path = session.read_json()
        expected_ptvsd_path = os.path.abspath(ptvsd.__file__)
        assert re.match(
            re.escape(expected_ptvsd_path) + r'(c|o)?$', ptvsd_path)

        session.wait_for_exit()
예제 #24
0
def _generate_system_info():
    def version_str(v):
        return '%d.%d.%d%s%d' % (v.major, v.minor, v.micro, v.releaselevel,
                                 v.serial)

    try:
        impl_name = sys.implementation.name
    except AttributeError:
        impl_name = ''

    try:
        impl_version = version_str(sys.implementation.version)
    except AttributeError:
        impl_version = ''

    return ANY.dict_with({
        'ptvsd': {
            'version': ptvsd.__version__,
        },
        'python': {
            'version': version_str(sys.version_info),
            'implementation': {
                'name': impl_name,
                'version': impl_version,
                'description': ANY.str,
            },
        },
        'platform': {
            'name': sys.platform,
        },
        'process': {
            'pid': ANY.int,
            'executable': sys.executable,
            'bitness': 64 if sys.maxsize > 2**32 else 32,
        },
    })
예제 #25
0
def test_flask_breakpoint_no_multiproc(bp_target, start_method):
    bp_file, bp_line, bp_name = {
        'code': (FLASK1_APP, 11, 'home'),
        'template': (FLASK1_TEMPLATE, 8, 'template')
    }[bp_target]

    with DebugSession() as session:
        _initialize_flask_session_no_multiproc(session, start_method)

        bp_var_content = 'Flask-Jinja-Test'
        session.set_breakpoints(bp_file, [bp_line])
        session.start_debugging()

        # wait for Flask web server to start
        wait_for_connection(FLASK_PORT)
        link = FLASK_LINK
        web_request = get_web_content(link, {})

        thread_stopped = session.wait_for_next(
            Event('stopped'), ANY.dict_with({'reason': 'breakpoint'}))
        assert thread_stopped.body['threadId'] is not None

        tid = thread_stopped.body['threadId']

        resp_stacktrace = session.send_request('stackTrace',
                                               arguments={
                                                   'threadId': tid,
                                               }).wait_for_response()
        assert resp_stacktrace.body['totalFrames'] > 0
        frames = resp_stacktrace.body['stackFrames']
        assert frames[0] == {
            'id': ANY.dap_id,
            'name': bp_name,
            'source': {
                'sourceReference': ANY.dap_id,
                'path': Path(bp_file),
            },
            'line': bp_line,
            'column': 1,
        }

        fid = frames[0]['id']
        resp_scopes = session.send_request('scopes',
                                           arguments={
                                               'frameId': fid
                                           }).wait_for_response()
        scopes = resp_scopes.body['scopes']
        assert len(scopes) > 0

        resp_variables = session.send_request(
            'variables',
            arguments={
                'variablesReference': scopes[0]['variablesReference']
            }).wait_for_response()
        variables = list(v for v in resp_variables.body['variables']
                         if v['name'] == 'content')
        assert variables == [{
            'name': 'content',
            'type': 'str',
            'value': repr(bp_var_content),
            'presentationHint': {
                'attributes': ['rawString']
            },
            'evaluateName': 'content'
        }]

        session.send_request('continue').wait_for_response(freeze=False)

        web_content = web_request.wait_for_response()
        assert web_content.find(bp_var_content) != -1

        # shutdown to web server
        link = FLASK_LINK + 'exit'
        get_web_content(link).wait_for_response()

        session.wait_for_exit()
예제 #26
0
def test_exceptions_and_partial_exclude_rules(pyfile, run_as, start_method,
                                              scenario):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        import backchannel
        import sys
        json = backchannel.read_json()
        call_me_back_dir = json['call_me_back_dir']
        sys.path.append(call_me_back_dir)

        import call_me_back

        def call_func():
            raise RuntimeError('unhandled error')  # @raise_line

        call_me_back.call_me_back(call_func)  # @call_me_back_line
        print('done')

    line_numbers = get_marked_line_numbers(code_to_debug)
    call_me_back_dir = get_test_root('call_me_back')

    if scenario == 'exclude_code_to_debug':
        rules = [{
            'path': '**/' + os.path.basename(code_to_debug),
            'include': False
        }]
    elif scenario == 'exclude_callback_dir':
        rules = [{'path': call_me_back_dir, 'include': False}]
    else:
        raise AssertionError('Unexpected scenario: %s' % (scenario, ))

    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            use_backchannel=True,
            rules=rules,
        )
        # TODO: The process returncode doesn't match the one returned from the DAP.
        # See: https://github.com/Microsoft/ptvsd/issues/1278
        session.expected_returncode = ANY.int
        filters = ['raised', 'uncaught']

        session.send_request('setExceptionBreakpoints', {
            'filters': filters
        }).wait_for_response()

        if scenario == 'exclude_code_to_debug':
            breakpoints = session.set_breakpoints(code_to_debug, [1])
            assert breakpoints == [{
                'verified':
                False,
                'message':
                ('Breakpoint in file excluded by filters.\n'
                 'Note: may be excluded because of "justMyCode" option (default == true).'
                 ),
                'source':
                ANY.dict_with({'path': Path(code_to_debug)}),
                'line':
                1
            }]

        session.start_debugging()
        session.write_json({'call_me_back_dir': call_me_back_dir})

        if scenario == 'exclude_code_to_debug':
            # Stop at handled
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            # We don't stop at the raise line but rather at the callback module which is
            # not excluded.
            assert len(frames) == 1
            assert frames[0] == ANY.dict_with({
                'line':
                2,
                'source':
                ANY.dict_with({
                    'path':
                    Path(os.path.join(call_me_back_dir, 'call_me_back.py'))
                })
            })
            # assert frames[1] == ANY.dict_with({ -- filtered out
            #     'line': line_numbers['call_me_back_line'],
            #     'source': ANY.dict_with({
            #         'path': Path(code_to_debug)
            #     })
            # })
            # 'continue' should terminate the debuggee
            session.send_request('continue').wait_for_response(freeze=False)

            # Note: does not stop at unhandled exception because raise was in excluded file.

        elif scenario == 'exclude_callback_dir':
            # Stop at handled raise_line
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert [(frame['name'], basename(frame['source']['path']))
                    for frame in frames] == [
                        ('call_func', 'code_to_debug.py'),
                        # ('call_me_back', 'call_me_back.py'), -- filtered out
                        ('<module>', 'code_to_debug.py'),
                    ]
            assert frames[0] == ANY.dict_with({
                'line':
                line_numbers['raise_line'],
                'source':
                ANY.dict_with({'path': Path(code_to_debug)})
            })
            session.send_request('continue').wait_for_response()

            # Stop at handled call_me_back_line
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert [(frame['name'], basename(frame['source']['path']))
                    for frame in frames] == [
                        ('<module>', 'code_to_debug.py'),
                    ]
            assert frames[0] == ANY.dict_with({
                'line':
                line_numbers['call_me_back_line'],
                'source':
                ANY.dict_with({'path': Path(code_to_debug)})
            })
            session.send_request('continue').wait_for_response()

            # Stop at unhandled
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert [(frame['name'], basename(frame['source']['path']))
                    for frame in frames] == [
                        ('call_func', 'code_to_debug.py'),
                        # ('call_me_back', 'call_me_back.py'), -- filtered out
                        ('<module>', 'code_to_debug.py'),
                    ]

            assert frames[0] == ANY.dict_with({
                'line':
                line_numbers['raise_line'],
                'source':
                ANY.dict_with({'path': Path(code_to_debug)})
            })
            session.send_request('continue').wait_for_response(freeze=False)
        else:
            raise AssertionError('Unexpected scenario: %s' % (scenario, ))

        session.wait_for_exit()
예제 #27
0
def test_condition_with_log_point(pyfile, run_as, start_method):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()
        a = 10
        for i in range(1, a):
            print('value: %d' % i)

    bp_line = 5
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
        )
        session.send_request('setBreakpoints',
                             arguments={
                                 'source': {
                                     'path': code_to_debug
                                 },
                                 'breakpoints': [{
                                     'line': bp_line,
                                     'logMessage': 'log: {a + i}',
                                     'condition': 'i==5'
                                 }],
                             }).wait_for_response()
        session.start_debugging()
        hit = session.wait_for_thread_stopped()
        frames = hit.stacktrace.body['stackFrames']
        assert bp_line == frames[0]['line']

        resp_scopes = session.send_request('scopes',
                                           arguments={
                                               'frameId': hit.frame_id
                                           }).wait_for_response()
        scopes = resp_scopes.body['scopes']
        assert len(scopes) > 0

        resp_variables = session.send_request(
            'variables',
            arguments={
                'variablesReference': scopes[0]['variablesReference']
            }).wait_for_response()
        variables = list(v for v in resp_variables.body['variables']
                         if v['name'] == 'i')
        assert variables == [
            ANY.dict_with({
                'name': 'i',
                'type': 'int',
                'value': '5',
                'evaluateName': 'i'
            })
        ]

        session.send_request('continue').wait_for_response(freeze=False)
        session.wait_for_exit()
        assert session.get_stderr_as_string() == b''

        output = session.all_occurrences_of(
            Event('output', ANY.dict_with({'category': 'stdout'})))
        output_str = ''.join(o.body['output'] for o in output)
        logged = sorted(
            int(i) for i in re.findall(r"log:\s([0-9]*)", output_str))
        values = sorted(
            int(i) for i in re.findall(r"value:\s([0-9]*)", output_str))

        assert 15 in logged
        assert 5 in values
예제 #28
0
def test_flask_breakpoint_multiproc(start_method):
    env = {
        'FLASK_APP': 'app',
        'FLASK_ENV': 'development',
        'FLASK_DEBUG': '1',
    }
    if platform.system() != 'Windows':
        locale = 'en_US.utf8' if platform.system(
        ) == 'Linux' else 'en_US.UTF-8'
        env.update({
            'LC_ALL': locale,
            'LANG': locale,
        })

    with DebugSession() as parent_session:
        parent_session.initialize(
            start_method=start_method,
            target=('module', 'flask'),
            multiprocess=True,
            program_args=['run', '--port', str(FLASK_PORT)],
            ignore_unobserved=[Event('stopped'),
                               Event('continued')],
            debug_options=['Jinja'],
            cwd=FLASK1_ROOT,
            env=env,
            expected_returncode=ANY.int,  # No clean way to kill Flask server
        )

        bp_line = 11
        bp_var_content = 'Flask-Jinja-Test'
        parent_session.set_breakpoints(FLASK1_APP, [bp_line])
        parent_session.start_debugging()

        with parent_session.connect_to_next_child_session() as child_session:
            child_session.send_request('setBreakpoints',
                                       arguments={
                                           'source': {
                                               'path': FLASK1_APP
                                           },
                                           'breakpoints': [
                                               {
                                                   'line': bp_line
                                               },
                                           ],
                                       }).wait_for_response()
            child_session.start_debugging()

            # wait for Flask server to start
            wait_for_connection(FLASK_PORT)
            web_request = get_web_content(FLASK_LINK, {})

            thread_stopped = child_session.wait_for_next(
                Event('stopped', ANY.dict_with({'reason': 'breakpoint'})))
            assert thread_stopped.body['threadId'] is not None

            tid = thread_stopped.body['threadId']

            resp_stacktrace = child_session.send_request(
                'stackTrace', arguments={
                    'threadId': tid,
                }).wait_for_response()
            assert resp_stacktrace.body['totalFrames'] > 0
            frames = resp_stacktrace.body['stackFrames']
            assert frames[0] == {
                'id': ANY.dap_id,
                'name': 'home',
                'source': {
                    'sourceReference': ANY.dap_id,
                    'path': Path(FLASK1_APP),
                },
                'line': bp_line,
                'column': 1,
            }

            fid = frames[0]['id']
            resp_scopes = child_session.send_request('scopes',
                                                     arguments={
                                                         'frameId': fid
                                                     }).wait_for_response()
            scopes = resp_scopes.body['scopes']
            assert len(scopes) > 0

            resp_variables = child_session.send_request(
                'variables',
                arguments={
                    'variablesReference': scopes[0]['variablesReference']
                }).wait_for_response()
            variables = [
                v for v in resp_variables.body['variables']
                if v['name'] == 'content'
            ]
            assert variables == [{
                'name': 'content',
                'type': 'str',
                'value': repr(bp_var_content),
                'presentationHint': {
                    'attributes': ['rawString']
                },
                'evaluateName': 'content'
            }]

            child_session.send_request('continue').wait_for_response(
                freeze=False)

            web_content = web_request.wait_for_response()
            assert web_content.find(bp_var_content) != -1

            # shutdown to web server
            link = FLASK_LINK + 'exit'
            get_web_content(link).wait_for_response()

            child_session.wait_for_termination()
            parent_session.wait_for_exit()
예제 #29
0
def test_exception_stack(pyfile, run_as, start_method, max_frames):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def do_something(n):
            if n <= 0:
                raise ArithmeticError('bad code')  # @unhandled
            do_something2(n - 1)

        def do_something2(n):
            do_something(n - 1)

        do_something(100)

    if max_frames == 'all':
        # trace back compresses repeated text
        min_expected_lines = 100
        max_expected_lines = 220
        args = {'maxExceptionStackFrames': 0}
    elif max_frames == 'default':
        # default is all frames
        min_expected_lines = 100
        max_expected_lines = 220
        args = {}
    else:
        min_expected_lines = 10
        max_expected_lines = 21
        args = {'maxExceptionStackFrames': 10}

    line_numbers = get_marked_line_numbers(code_to_debug)
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued')],
            expected_returncode=ANY.int,
            args=args,
        )
        session.send_request('setExceptionBreakpoints', {
            'filters': ['uncaught']
        }).wait_for_response()
        session.start_debugging()

        hit = session.wait_for_thread_stopped(reason='exception')
        frames = hit.stacktrace.body['stackFrames']
        assert frames[0]['line'] == line_numbers['unhandled']

        resp_exc_info = session.send_request('exceptionInfo', {
            'threadId': hit.thread_id
        }).wait_for_response()

        expected = ANY.dict_with({
            'exceptionId':
            Regex('ArithmeticError'),
            'description':
            'bad code',
            'breakMode':
            'unhandled',
            'details':
            ANY.dict_with({
                'typeName': Regex('ArithmeticError'),
                'message': 'bad code',
                'source': Path(code_to_debug),
            }),
        })
        assert resp_exc_info.body == expected
        stack_str = resp_exc_info.body['details']['stackTrace']
        stack_line_count = len(stack_str.split('\n'))
        assert min_expected_lines <= stack_line_count <= max_expected_lines

        session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()
예제 #30
0
def test_vsc_exception_options_raise_without_except(pyfile, run_as,
                                                    start_method, raised,
                                                    uncaught):
    @pyfile
    def code_to_debug():
        from dbgimporter import import_and_enable_debugger
        import_and_enable_debugger()

        def raise_without_except():
            raise ArithmeticError('bad code')  # @exception_line

        raise_without_except()

    line_numbers = get_marked_line_numbers(code_to_debug)
    ex_line = line_numbers['exception_line']
    filters = []
    filters += ['raised'] if raised == 'raisedOn' else []
    filters += ['uncaught'] if uncaught == 'uncaughtOn' else []
    with DebugSession() as session:
        session.initialize(
            target=(run_as, code_to_debug),
            start_method=start_method,
            ignore_unobserved=[Event('continued'),
                               Event('stopped')],
            expected_returncode=ANY.int,
        )
        session.send_request('setExceptionBreakpoints', {
            'filters': filters
        }).wait_for_response()
        session.start_debugging()

        expected = ANY.dict_with({
            'exceptionId':
            ANY.such_that(lambda s: s.endswith('ArithmeticError')),
            'description':
            'bad code',
            'breakMode':
            'always' if raised == 'raisedOn' else 'unhandled',
            'details':
            ANY.dict_with({
                'typeName':
                ANY.such_that(lambda s: s.endswith('ArithmeticError')),
                'message':
                'bad code',
                'source':
                Path(code_to_debug),
            }),
        })

        if raised == 'raisedOn':
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert ex_line == frames[0]['line']

            resp_exc_info = session.send_request('exceptionInfo', {
                'threadId': hit.thread_id
            }).wait_for_response()

            assert resp_exc_info.body == expected
            session.send_request('continue').wait_for_response(freeze=False)

            # NOTE: debugger stops at each frame if raised and is uncaught
            # This behavior can be changed by updating 'notify_on_handled_exceptions'
            # setting we send to pydevd to notify only once. In our test code, we have
            # two frames, hence two stops.
            session.wait_for_thread_stopped(reason='exception')
            session.send_request('continue').wait_for_response(freeze=False)

        if uncaught == 'uncaughtOn':
            hit = session.wait_for_thread_stopped(reason='exception')
            frames = hit.stacktrace.body['stackFrames']
            assert ex_line == frames[0]['line']

            resp_exc_info = session.send_request('exceptionInfo', {
                'threadId': hit.thread_id
            }).wait_for_response()

            expected = ANY.dict_with({
                'exceptionId':
                ANY.such_that(lambda s: s.endswith('ArithmeticError')),
                'description':
                'bad code',
                'breakMode':
                'unhandled',  # Only difference from previous expected is breakMode.
                'details':
                ANY.dict_with({
                    'typeName':
                    ANY.such_that(lambda s: s.endswith('ArithmeticError')),
                    'message':
                    'bad code',
                    'source':
                    Path(code_to_debug),
                }),
            })

            assert resp_exc_info.body == expected
            session.send_request('continue').wait_for_response(freeze=False)

        session.wait_for_exit()