Exemple #1
0
    def run_test_reattach(self, debug_info):
        options = {'debugOptions': ['RedirectOutput']}
        with self.start_debugging(debug_info) as dbg:
            session = dbg.session
            stopped1 = session.get_awaiter_for_event('stopped')
            (_, req_launch_attach, _, _, _, _) = lifecycle_handshake(
                session,
                debug_info.starttype,
                options=options,
                threads=True)
            Awaitable.wait_all(req_launch_attach, stopped1)

            thread_id = stopped1.event.body['threadId']
            req_disconnect = session.send_request('disconnect', restart=False)
            req_disconnect.wait()

            time.sleep(1)
            (_, req_launch_attach, _, _, _, _) = lifecycle_handshake(
                session,
                debug_info.starttype,
                options=options,
                threads=True)
            Awaitable.wait_all(req_launch_attach)

            self.set_var_to_end_loop(session, thread_id)
            session.send_request('continue', threadId=thread_id)

        received = list(_strip_newline_output_events(session.received))
        self.assert_contains(received, [
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
Exemple #2
0
    def run_test_breaking_into_unhandled_exceptions(self, debug_info,
                                                    expected_source_name):
        excbreakpoints = [{'filters': ['uncaught']}]
        options = {'debugOptions': ['RedirectOutput']}

        with self.start_debugging(debug_info) as dbg:
            stopped = dbg.session.get_awaiter_for_event('stopped')
            (_, req_launch_attach, _, _, _, _) = lifecycle_handshake(
                dbg.session,
                debug_info.starttype,
                excbreakpoints=excbreakpoints,
                options=options,
                threads=True)

            req_launch_attach.wait(timeout=3.0)
            stopped.wait(timeout=3.0)
            self.assertEqual(stopped.event.body['text'], 'ArithmeticError')
            self.assertEqual(stopped.event.body['description'], 'Hello')

            thread_id = stopped.event.body['threadId']
            req_exc_info = dbg.session.send_request(
                'exceptionInfo',
                threadId=thread_id,
            )
            req_exc_info.wait()
            exc_info = req_exc_info.resp.body

            self.assert_is_subset(
                exc_info, {
                    'exceptionId': 'ArithmeticError',
                    'breakMode': 'unhandled',
                    'details': {
                        'typeName': 'ArithmeticError',
                        'source': expected_source_name
                    }
                })

            continued = dbg.session.get_awaiter_for_event('continued')
            dbg.session.send_request(
                'continue',
                threadId=thread_id,
            ).wait()
            Awaitable.wait_all(continued)

        received = list(_strip_newline_output_events(dbg.session.received))
        # TODO: Re-enable after fixing #685
        #self.assertEqual(
        #    len(self.find_events(received, 'output', {'category': 'stdout'})),
        #    1)
        std_errs = self.find_events(received, 'output', {'category': 'stderr'})
        self.assertGreaterEqual(len(std_errs), 1)
        std_err_msg = ''.join([msg.body['output'] for msg in std_errs])
        self.assertIn('ArithmeticError: Hello', std_err_msg)
        self.assert_contains(received, [
            self.new_event('continued', threadId=thread_id),
            # TODO: Re-enable after fixing #685
            # self.new_event('output', category='stdout', output='one'),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
Exemple #3
0
    def test_attach_embedded(self):
        lockfile = self.workspace.lockfile()
        done, waitscript = lockfile.wait_in_script()
        addr = Address('localhost', 8888)
        script = dedent("""
            from __future__ import print_function
            import sys
            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output={})
            ptvsd.wait_for_attach()

            print('success!', end='')

            %s
            """).format(os.getcwd(), tuple(addr), True)
        filename = self.write_script('spam.py', script % waitscript)
        with DebugAdapter.start_embedded(addr, filename) as adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter)

                (req_initialize, req_launch, req_config, _, _,
                 _) = lifecycle_handshake(session, 'attach')
                Awaitable.wait_all(req_initialize, req_launch)
                done()
                adapter.wait()

        for i in range(10):
            # It could take some additional time for the adapter
            # to actually get the success output, so, wait for the
            # expected condition in a busy loop.
            out = adapter.output.decode('utf-8')
            if 'success!' in out:
                break
            import time
            time.sleep(.1)

        received = list(_strip_newline_output_events(session.received))
        self.assert_contains(received, [
            self.new_version_event(session.received),
            self.new_response(req_initialize.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_launch.req),
            self.new_response(req_config.req),
            self.new_event(
                'process', **{
                    'isLocalProcess': True,
                    'systemProcessId': adapter.pid,
                    'startMethod': 'attach',
                    'name': filename,
                }),
            self.new_event('output', output='success!', category='stdout'),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
        self.assertIn('success!', out)
Exemple #4
0
    def run_test_breaking_into_handled_exceptions(self, debug_info):
        excbreakpoints = [{'filters': ['raised', 'uncaught']}]
        options = {'debugOptions': ['RedirectOutput']}

        with self.start_debugging(debug_info) as dbg:
            stopped = dbg.session.get_awaiter_for_event('stopped')
            (_, req_launch_attach, _, _, _,
             _) = lifecycle_handshake(dbg.session,
                                      debug_info.starttype,
                                      excbreakpoints=excbreakpoints,
                                      options=options,
                                      threads=True)

            Awaitable.wait_all(req_launch_attach, stopped)
            self.assertEqual(stopped.event.body['text'], 'ArithmeticError')
            self.assertIn("ArithmeticError('Hello'",
                          stopped.event.body['description'])

            thread_id = stopped.event.body['threadId']
            req_exc_info = dbg.session.send_request(
                'exceptionInfo',
                threadId=thread_id,
            )
            req_exc_info.wait()
            exc_info = req_exc_info.resp.body

            self.assert_is_subset(
                exc_info,
                {
                    'exceptionId': 'ArithmeticError',
                    'breakMode': 'always',
                    'details': {
                        'typeName': 'ArithmeticError',
                        # 'source': debug_info.filename
                    }
                })

            continued = dbg.session.get_awaiter_for_event('continued')
            dbg.session.send_request(
                'continue',
                threadId=thread_id,
            ).wait()
            Awaitable.wait_all(continued)

        received = list(_strip_newline_output_events(dbg.session.received))
        self.assert_contains(received, [
            self.new_event('continued', threadId=thread_id),
            self.new_event('output', category='stdout', output='end'),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
Exemple #5
0
    def run_test_breaking_into_raised_exceptions_only(self, debug_info,
                                                      expected_source_name):
        # NOTE: for this case we will be using a unhandled exception. The
        # behavior expected here is that it breaks once when the exception
        # was raised but not during postmortem
        excbreakpoints = [{'filters': ['raised']}]
        options = {'debugOptions': ['RedirectOutput']}

        with self.start_debugging(debug_info) as dbg:
            stopped = dbg.session.get_awaiter_for_event('stopped')
            (_, req_launch_attach, _, _, _,
             _) = lifecycle_handshake(dbg.session,
                                      debug_info.starttype,
                                      excbreakpoints=excbreakpoints,
                                      options=options)

            Awaitable.wait_all(req_launch_attach, stopped)
            self.assertEqual(stopped.event.body['text'], 'ArithmeticError')
            self.assertEqual(stopped.event.body['description'], 'Hello')

            thread_id = stopped.event.body['threadId']
            req_exc_info = dbg.session.send_request('exceptionInfo',
                                                    threadId=thread_id)
            req_exc_info.wait()
            exc_info = req_exc_info.resp.body

            self.assert_is_subset(
                exc_info, {
                    'exceptionId': 'ArithmeticError',
                    'breakMode': 'always',
                    'details': {
                        'typeName': 'ArithmeticError',
                        'source': expected_source_name
                    }
                })

            continued = dbg.session.get_awaiter_for_event('continued')
            dbg.session.send_request(
                'continue',
                threadId=thread_id,
            ).wait()
            Awaitable.wait_all(continued)

        received = list(_strip_newline_output_events(dbg.session.received))
        self.assert_contains(received, [
            self.new_event('continued', threadId=thread_id),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
Exemple #6
0
    def run_test_termination(self, debug_info):
        with self.start_debugging(debug_info) as dbg:
            session = dbg.session

            exited = session.get_awaiter_for_event('exited')
            terminated = session.get_awaiter_for_event('terminated')

            (_, req_launch, _, _, _,
             _) = lifecycle_handshake(dbg.session,
                                      debug_info.starttype,
                                      threads=True)

            Awaitable.wait_all(req_launch,
                               session.get_awaiter_for_event('thread'))
            disconnect = session.send_request('disconnect')

            Awaitable.wait_all(exited, terminated, disconnect)
Exemple #7
0
    def run_test_attach_or_launch(self, debug_info, end_loop=False):
        options = {'debugOptions': ['RedirectOutput']}
        with self.start_debugging(debug_info) as dbg:
            session = dbg.session
            stopped = session.get_awaiter_for_event('stopped')
            (_, req_launch_attach, _, _, _, _) = lifecycle_handshake(
                session,
                debug_info.starttype,
                options=options)
            Awaitable.wait_all(req_launch_attach, stopped)
            thread_id = stopped.event.body['threadId']
            if end_loop:
                self.set_var_to_end_loop(session, thread_id)
            session.send_request('continue', threadId=thread_id)

        received = list(_strip_newline_output_events(dbg.session.received))
        self.assert_contains(received, [
            self.new_event('output', category='stdout', output='one'),
            self.new_event('output', category='stdout', output='two'),
            self.new_event('continued', threadId=thread_id),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
Exemple #8
0
    def run_test_with_unhandled_exception(self, debug_info, framework,
                                          expected_source_name):
        if (debug_info.starttype == 'attach'):
            pathMappings = []
            pathMappings.append({
                'localRoot': debug_info.cwd,
                'remoteRoot': debug_info.cwd
            })
            options = {
                'debugOptions': ['RedirectOutput', framework],
                'pathMappings': pathMappings
            }
        else:
            options = {'debugOptions': ['RedirectOutput', framework]}

        excbreakpoints = [{'filters': ['raised', 'uncaught']}]
        with self.start_debugging(debug_info) as dbg:
            session = dbg.session
            with session.wait_for_event('stopped') as result:
                (
                    _,
                    req_launch_attach,
                    _,
                    _,
                    _,
                    _,
                ) = lifecycle_handshake(session,
                                        debug_info.starttype,
                                        options=options,
                                        excbreakpoints=excbreakpoints)
                req_launch_attach.wait()

                # wait for flask web server start
                count = 0
                base_path = None
                while base_path is None and count < 10:
                    outevent = session.get_awaiter_for_event('output')
                    Awaitable.wait_all(outevent)
                    events = self.find_events(session.received, 'output')
                    count += 1
                    for e in events:
                        matches = re.findall(re_link, e.body['output'])
                        if len(matches) > 0 and len(matches[0]) > 0 and \
                           len(matches[0][0].strip()) > 0:
                            base_path = matches[0][0]
                            break

                # connect to web server
                path = base_path + \
                    'unhandled' if base_path.endswith('/') else '/unhandled'
                web_result = {}
                web_client_thread = threading.Thread(
                    target=get_web_string_no_error,
                    args=(path, web_result),
                    name='test.webClient')

                web_client_thread.start()

            event = result['msg']
            thread_id = event.body['threadId']

            req_exc_info = dbg.session.send_request(
                'exceptionInfo',
                threadId=thread_id,
            )
            req_exc_info.wait()
            exc_info = req_exc_info.resp.body

            self.assert_is_subset(
                exc_info, {
                    'exceptionId': 'ArithmeticError',
                    'breakMode': 'always',
                    'details': {
                        'typeName': 'ArithmeticError',
                        'source': expected_source_name
                    }
                })

            continued = dbg.session.get_awaiter_for_event('continued')
            dbg.session.send_request(
                'continue',
                threadId=thread_id,
            ).wait()
            Awaitable.wait_all(continued)

            # Shutdown webserver
            path = base_path + 'exit' if base_path.endswith('/') else '/exit'
            web_client_thread = threading.Thread(
                target=get_web_string_no_error,
                args=(path, None),
                name='test.webClient.shutdown')
            web_client_thread.start()
            web_client_thread.join(timeout=1)

        received = list(_strip_newline_output_events(dbg.session.received))
        if framework != 'Django':
            # TODO: Figure out better way to shutdown Django
            self.assert_contains(received, [
                self.new_event('exited', exitCode=0),
                self.new_event('terminated'),
            ])
Exemple #9
0
    def run_test_with_break_points(self, debug_info, **kwargs):
        bp_filename = kwargs.pop('bp_filename')
        bp_line = kwargs.pop('bp_line')
        bp_name = kwargs.pop('bp_name')
        bp_var_value = kwargs.pop('bp_var_value')
        framework = kwargs.pop('framework', 'Django')
        if (debug_info.starttype == 'attach'):
            pathMappings = []
            pathMappings.append({
                'localRoot': debug_info.cwd,
                'remoteRoot': debug_info.cwd
            })
            options = {
                'debugOptions': ['RedirectOutput', framework],
                'pathMappings': pathMappings
            }
        else:
            options = {'debugOptions': ['RedirectOutput', framework]}

        breakpoints = [{
            'source': {
                'path': bp_filename
            },
            'breakpoints': [{
                'line': bp_line
            }]
        }]

        with self.start_debugging(debug_info) as dbg:
            session = dbg.session
            with session.wait_for_event('stopped') as result:
                (
                    _,
                    req_launch_attach,
                    _,
                    _,
                    _,
                    _,
                ) = lifecycle_handshake(session,
                                        debug_info.starttype,
                                        options=options,
                                        breakpoints=breakpoints)
                req_launch_attach.wait()

                # wait for flask web server start
                count = 0
                path = None
                while path is None and count < 10:
                    outevent = session.get_awaiter_for_event('output')
                    Awaitable.wait_all(outevent)
                    events = self.find_events(session.received, 'output')
                    count += 1
                    for e in events:
                        matches = re.findall(re_link, e.body['output'])
                        if len(matches) > 0 and len(matches[0]) > 0 and \
                            len(matches[0][0].strip()) > 0:
                            path = matches[0][0]
                            break

                # connect to web server
                web_result = {}
                web_client_thread = threading.Thread(
                    target=get_web_string_no_error,
                    args=(path, web_result),
                    name='test.webClient')

                web_client_thread.start()

            event = result['msg']
            tid = event.body['threadId']

            req_stacktrace = session.send_request(
                'stackTrace',
                threadId=tid,
            )
            req_stacktrace.wait()
            stacktrace = req_stacktrace.resp.body

            frame_id = stacktrace['stackFrames'][0]['id']
            req_scopes = session.send_request(
                'scopes',
                frameId=frame_id,
            )
            req_scopes.wait()
            scopes = req_scopes.resp.body['scopes']
            variables_reference = scopes[0]['variablesReference']
            req_variables = session.send_request(
                'variables',
                variablesReference=variables_reference,
            )
            req_variables.wait()
            variables = req_variables.resp.body['variables']

            session.send_request(
                'continue',
                threadId=tid,
            )

            # wait for flask rendering thread to exit
            web_client_thread.join(timeout=0.1)

            # shutdown to web server
            path += 'exit' if path.endswith('/') else '/exit'
            web_client_thread = threading.Thread(
                target=get_web_string_no_error,
                args=(path, None),
                name='test.webClient.shutdown')
            web_client_thread.start()
            web_client_thread.join(timeout=1)

        received = list(_strip_newline_output_events(session.received))

        self.assertGreaterEqual(stacktrace['totalFrames'], 1)
        self.assert_is_subset(
            stacktrace,
            {
                # We get Python and PTVSD frames as well.
                # 'totalFrames': 2,
                'stackFrames': [{
                    'id': 1,
                    'name': bp_name,
                    'source': {
                        'sourceReference': 0,
                        'path': bp_filename
                    },
                    'line': bp_line,
                    'column': 1,
                }],
            })
        variables = list(v for v in variables if v['name'] == 'content')
        self.assert_is_subset(variables, [{
            'name': 'content',
            'type': 'str',
            'value': repr(bp_var_value),
            'presentationHint': {
                'attributes': ['rawString']
            },
            'evaluateName': 'content'
        }])
        self.assertTrue(web_result['content'].find(bp_var_value) != -1)
        self.assert_contains(received, [
            self.new_event(
                'stopped',
                reason='breakpoint',
                threadId=tid,
                text=None,
                description=None,
            ),
            self.new_event('continued', threadId=tid),
        ])

        if framework != 'Django':
            # TODO: Figure out better way to shutdown Django
            self.assert_contains(received, [
                self.new_event('exited', exitCode=0),
                self.new_event('terminated'),
            ])
Exemple #10
0
    def test_attach_breakpoints(self):
        # See https://github.com/Microsoft/ptvsd/issues/448.
        addr = Address('localhost', 8888)
        filename = self.write_script('spam.py', """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd

            addr = {}
            ptvsd.enable_attach(addr)
            print('== waiting for attach ==')
            # <waiting>
            ptvsd.wait_for_attach()
            # <attached>
            print('== attached! ==')
            # <bp 2>
            print('== done waiting ==')
            """.format(ROOT, tuple(addr)))
        lockfile1 = self.workspace.lockfile()
        done1, _ = set_lock(filename, lockfile1, 'waiting')
        lockfile2 = self.workspace.lockfile()
        done2, script = set_lock(filename, lockfile2, 'bp 2')

        bp1 = find_line(script, 'attached')
        bp2 = find_line(script, 'bp 2')
        breakpoints = [{
            'source': {'path': filename},
            'breakpoints': [
                {'line': bp1},
                {'line': bp2},
            ],
        }]

        options = {
            'pathMappings': [
                {
                    'localRoot': os.path.dirname(filename),
                    'remoteRoot': os.path.dirname(filename)
                },
                # This specific mapping is for Mac.
                # For some reason temp paths on Mac get prefixed with
                # `private` when returned from ptvsd.
                {
                    'localRoot': os.path.dirname(filename),
                    'remoteRoot': '/private' + os.path.dirname(filename)
                }
            ]
        }

        #DebugAdapter.VERBOSE = True
        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter, timeout=5)

                with session.wait_for_event('thread') as result:
                    with session.wait_for_event('process'):
                        (req_init, req_attach, req_config,
                         reqs_bps, _, req_threads1,
                         ) = lifecycle_handshake(session, 'attach',
                                                 breakpoints=breakpoints,
                                                 options=options,
                                                 threads=True)
                        Awaitable.wait_all(req_init, req_attach, req_config)
                        req_bps, = reqs_bps  # There should only be one.
                event = result['msg']
                tid = event.body['threadId']

                # Grab the initial output.
                out1 = next(adapter.output)  # "waiting for attach"
                line = adapter.output.readline()
                while line:
                    out1 += line
                    line = adapter.output.readline()

                with session.wait_for_event('stopped'):
                    # Tell the script to proceed (at "# <waiting>").
                    # This leads to the first breakpoint.
                    done1()
                req_threads2, req_stacktrace1 = react_to_stopped(session, tid)
                out2 = str(adapter.output)  # ""

                # Tell the script to proceed (at "# <bp 2>").  This
                # leads to the second breakpoint.  At this point
                # execution is still stopped at the first breakpoint.
                done2()
                with session.wait_for_event('stopped'):
                    with session.wait_for_event('continued'):
                        req_continue1 = session.send_request(
                            'continue',
                            threadId=tid,
                        )
                        req_continue1.wait()
                req_threads3, req_stacktrace2 = react_to_stopped(session, tid)
                out3 = str(adapter.output)  # "attached!"

                with session.wait_for_event('continued'):
                    req_continue2 = session.send_request(
                        'continue',
                        threadId=tid,
                    )
                    req_continue2.wait()

                adapter.wait()
            out4 = str(adapter.output)  # "done waiting"

        # Output between enable_attach() and wait_for_attach() may
        # be sent at a relatively arbitrary time (or not at all).
        # So we ignore it by removing it from the message list.
        received = list(_strip_output_event(session.received,
                                            u'== waiting for attach =='))
        received = list(_strip_newline_output_events(received))
        # There's an ordering race with continue/continued that pops
        # up occasionally.  We work around that by manually fixing the
        # order.
        for pos, msg in _find_events(received, 'continued'):
            prev = received[pos-1]
            if prev.type != 'response' or prev.command != 'continue':
                received.pop(pos-1)
                received.insert(pos + 1, prev)
        # Sometimes the proc ends before the exited and terminated
        # events are received.
        received = list(_strip_exit(received))
        self.assert_contains(received, [
            self.new_version_event(session.received),
            self.new_response(req_init.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_attach.req),
            self.new_event(
                'thread',
                threadId=tid,
                reason='started',
            ),
            self.new_response(req_threads1.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_bps.req, **{
                'breakpoints': [{
                    'id': 1,
                    'line': bp1,
                    'verified': True,
                }, {
                    'id': 2,
                    'line': bp2,
                    'verified': True,
                }],
            }),
            self.new_response(req_config.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_event(
                'stopped',
                threadId=tid,
                reason='breakpoint',
                description=None,
                text=None,
            ),
            self.new_response(req_threads2.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_event(
                'module',
                module={
                    'id': 1,
                    'name': '__main__',
                    'path': filename,
                    'package': None,
                },
                reason='new',
            ),
            self.new_response(req_stacktrace1.req, **{
                'totalFrames': 1,
                'stackFrames': [{
                    'id': 1,
                    'name': '<module>',
                    'source': {
                        'path': filename,
                        'sourceReference': 0,
                    },
                    'line': bp1,
                    'column': 1,
                }],
            }),
            self.new_response(req_continue1.req, **{
                'allThreadsContinued': True
            }),
            self.new_event('continued', threadId=tid),
            self.new_event(
                'output',
                category='stdout',
                output='== attached! ==',
            ),
            self.new_event(
                'stopped',
                threadId=tid,
                reason='breakpoint',
                description=None,
                text=None,
            ),
            self.new_response(req_threads3.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_stacktrace2.req, **{
                'totalFrames': 1,
                'stackFrames': [{
                    'id': 2,  # TODO: Isn't this the same frame as before?
                    'name': '<module>',
                    'source': {
                        'path': filename,
                        'sourceReference': 0,
                    },
                    'line': bp2,
                    'column': 1,
                }],
            }),
            self.new_response(req_continue2.req, **{
                'allThreadsContinued': True
            }),
            self.new_event('continued', threadId=tid),
            self.new_event(
                'output',
                category='stdout',
                output='== done waiting ==',
            ),
            #self.new_event(
            #    'thread',
            #    threadId=tid,
            #    reason='exited',
            #),
            #self.new_event('exited', exitCode=0),
            #self.new_event('terminated'),
        ])
        # before attaching
        self.assertIn(b'waiting for attach', out1)
        self.assertNotIn(b'attached!', out1)
        # after attaching
        self.assertNotIn('attached!', out2)
        # after bp1 continue
        self.assertIn('attached!', out3)
        self.assertNotIn('done waiting', out3)
        # after bp2 continue
        self.assertIn('done waiting', out4)
Exemple #11
0
    def test_detach_clear_and_resume(self):
        addr = Address('localhost', 8888)
        filename = self.write_script('spam.py', """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd

            addr = {}
            ptvsd.enable_attach(addr)
            ptvsd.wait_for_attach()

            # <before>
            print('==before==')

            # <after>
            print('==after==')

            # <done>
            """.format(ROOT, tuple(addr)))
        lockfile2 = self.workspace.lockfile()
        done1, _ = set_lock(filename, lockfile2, 'before')
        lockfile3 = self.workspace.lockfile()
        _, wait2 = set_release(filename, lockfile3, 'done')
        lockfile4 = self.workspace.lockfile()
        done2, script = set_lock(filename, lockfile4, 'done')

        bp1 = find_line(script, 'before')
        bp2 = find_line(script, 'after')

        #DebugAdapter.VERBOSE = True
        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            with DebugClient() as editor:
                session1 = editor.attach_socket(addr, adapter, timeout=5)
                with session1.wait_for_event('thread') as result:
                    with session1.wait_for_event('process'):
                        (req_init1, req_attach1, req_config1,
                         _, _, req_threads1,
                         ) = lifecycle_handshake(session1, 'attach',
                                                 threads=True)
                event = result['msg']
                tid1 = event.body['threadId']

                stopped_event = session1.get_awaiter_for_event('stopped')
                req_bps = session1.send_request(
                    'setBreakpoints',
                    source={'path': filename},
                    breakpoints=[
                        {'line': bp1},
                        {'line': bp2},
                    ],
                )
                req_bps.wait()

                done1()
                stopped_event.wait()

                req_threads2 = session1.send_request('threads')
                req_stacktrace1 = session1.send_request(
                    'stackTrace',
                    threadId=tid1,
                )
                out1 = str(adapter.output)

                # Detach with execution stopped and 1 breakpoint left.
                req_disconnect = session1.send_request('disconnect')
                Awaitable.wait_all(req_threads2, req_stacktrace1, req_disconnect) # noqa
                editor.detach(adapter)
                try:
                    wait2()
                except LockTimeoutError:
                    self.fail('execution never resumed upon detach '
                              'or breakpoints never cleared')
                out2 = str(adapter.output)
                import time
                time.sleep(2)
                session2 = editor.attach_socket(addr, adapter, timeout=5)
                #session2.VERBOSE = True
                with session2.wait_for_event('thread') as result:
                    with session2.wait_for_event('process'):
                        (req_init2, req_attach2, req_config2,
                         _, _, req_threads3,
                         ) = lifecycle_handshake(session2, 'attach',
                                                 threads=True)
                event = result['msg']
                tid2 = event.body['threadId']

                done2()
                adapter.wait()
            out3 = str(adapter.output)

        received = list(_strip_newline_output_events(session1.received))
        self.assert_contains(received, [
            self.new_version_event(session1.received),
            self.new_response(req_init1.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_attach1.req),
            self.new_event(
                'thread',
                threadId=tid1,
                reason='started',
            ),
            self.new_response(req_threads1.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_config1.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_response(req_bps.req, **{
                'breakpoints': [{
                    'id': 1,
                    'line': bp1,
                    'verified': True,
                }, {
                    'id': 2,
                    'line': bp2,
                    'verified': True,
                }],
            }),
            self.new_event(
                'stopped',
                threadId=tid1,
                reason='breakpoint',
                description=None,
                text=None,
            ),
            self.new_response(req_threads2.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_disconnect.req),
        ])
        self.messages.reset_all()
        received = list(_strip_newline_output_events(session2.received))
        # Sometimes the proc ends before the exited and terminated
        # events are received.
        received = list(_strip_exit(received))
        self.assert_contains(received, [
            self.new_version_event(session2.received),
            self.new_response(req_init2.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_attach2.req),
            self.new_event(
                'thread',
                threadId=tid2,
                reason='started',
            ),
            self.new_response(req_threads3.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_config2.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            #self.new_event(
            #    'thread',
            #    threadId=tid2,
            #    reason='exited',
            #),
            #self.new_event('exited', exitCode=0),
            #self.new_event('terminated'),
        ])
        # at breakpoint
        self.assertEqual(out1, '')
        # after detaching
        self.assertIn('==before==', out2)
        self.assertIn('==after==', out2)
        # after reattach
        self.assertEqual(out3, out2)
Exemple #12
0
    def run_test_breaking_into_raised_and_unhandled_exceptions(
        self, debug_info, expected_source_name):
        excbreakpoints = [{'filters': ['raised', 'uncaught']}]
        options = {'debugOptions': ['RedirectOutput']}

        expected = {
            'exceptionId': 'ArithmeticError',
            'breakMode': 'always',
            'details': {
                'typeName': 'ArithmeticError',
                'source': expected_source_name
            }
        }

        with self.start_debugging(debug_info) as dbg:
            stopped = dbg.session.get_awaiter_for_event('stopped')
            (_, req_launch_attach, _, _, _, _
             ) = lifecycle_handshake(dbg.session, debug_info.starttype,
                                     excbreakpoints=excbreakpoints,
                                     options=options)

            Awaitable.wait_all(req_launch_attach, stopped)
            self.assertEqual(stopped.event.body['text'], 'ArithmeticError')
            self.assertEqual(stopped.event.body['description'], 'Hello')

            thread_id = stopped.event.body['threadId']
            req_exc_info = dbg.session.send_request(
                'exceptionInfo',
                threadId=thread_id)
            req_exc_info.wait()
            self.assert_is_subset(req_exc_info.resp.body, expected)

            stopped2 = dbg.session.get_awaiter_for_event('stopped')
            continued = dbg.session.get_awaiter_for_event('continued')
            dbg.session.send_request(
                'continue',
                threadId=thread_id,
            ).wait()
            Awaitable.wait_all(stopped2, continued)

            # Second hit on uncaught exception
            self.assertEqual(stopped2.event.body['text'], 'ArithmeticError')
            self.assertEqual(stopped2.event.body['description'], 'Hello')

            req_exc_info2 = dbg.session.send_request(
                'exceptionInfo',
                threadId=thread_id,
            )
            req_exc_info2.wait()
            self.assert_is_subset(req_exc_info2.resp.body, expected)

            continued2 = dbg.session.get_awaiter_for_event('continued')
            dbg.session.send_request(
                'continue',
                threadId=thread_id,
            ).wait()
            Awaitable.wait_all(continued2)

        received = list(_strip_newline_output_events(dbg.session.received))
        self.assert_contains(received, [
            self.new_event('continued', threadId=thread_id),
            self.new_event('continued', threadId=thread_id),  # expect 2 events
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
Exemple #13
0
    def run_test_variables(self, debug_info):
        bp_line = 3
        breakpoints = [{
            'source': {
                'path': debug_info.filename
            },
            'breakpoints': [{
                'line': bp_line
            }]
        }]

        with self.start_debugging(debug_info) as dbg:
            session = dbg.session
            with session.wait_for_event('stopped') as result:
                (
                    _,
                    req_launch_attach,
                    _,
                    _,
                    _,
                    _,
                ) = lifecycle_handshake(session,
                                        debug_info.starttype,
                                        breakpoints=breakpoints)
                req_launch_attach.wait()
            event = result['msg']
            tid = event.body['threadId']

            req_stacktrace = session.send_request(
                'stackTrace',
                threadId=tid,
            )
            req_stacktrace.wait()
            frames = req_stacktrace.resp.body['stackFrames']
            frame_id = frames[0]['id']
            req_scopes = session.send_request(
                'scopes',
                frameId=frame_id,
            )
            req_scopes.wait()
            scopes = req_scopes.resp.body['scopes']
            variables_reference = scopes[0]['variablesReference']
            req_variables = session.send_request(
                'variables',
                variablesReference=variables_reference,
            )
            req_variables.wait()
            variables = req_variables.resp.body['variables']

            var_b = list(b for b in variables if b['name'] == 'b')
            var_b = var_b[0] if len(var_b) == 1 else None
            if var_b is None:
                var_b_variables = None
            else:
                var_b_ref = var_b['variablesReference']
                req_variables = session.send_request(
                    'variables',
                    variablesReference=var_b_ref,
                )
                req_variables.wait()
                var_b_variables = req_variables.resp.body['variables']

            req_evaluate1 = session.send_request(
                'evaluate',
                expression='a',
                frameId=frame_id,
            )
            req_evaluate2 = session.send_request(
                'evaluate',
                expression="b['one']",
                frameId=frame_id,
            )
            Awaitable.wait_all(req_evaluate1, req_evaluate2)
            var_a_evaluate = req_evaluate1.resp.body
            var_b_one_evaluate = req_evaluate2.resp.body

            session.send_request('continue', threadId=tid)

        # Variables for a, b, __file__, __main__
        self.assertGreaterEqual(len(variables), 3)
        self.assert_is_subset(variables, [{
            'name': 'a',
            'type': 'int',
            'value': '1',
            'evaluateName': 'a'
        }, {
            'name': 'b',
            'type': 'dict',
            'value': "{'one': 1, 'two': 2}",
            'evaluateName': 'b'
        }, {
            'name': '__builtins__',
            'type': 'dict',
            'evaluateName': '__builtins__'
        }, {
            'name': '__doc__',
            'type': 'NoneType',
            'value': 'None',
            'evaluateName': '__doc__'
        }, {
            'name': '__file__',
            'type': 'str',
            'presentationHint': {
                'attributes': ['rawString']
            },
            'evaluateName': '__file__'
        }, {
            'name': '__loader__',
            'type': 'SourceFileLoader',
            'evaluateName': '__loader__'
        }, {
            'name': '__name__',
            'type': 'str',
            'value': "'__main__'",
            'presentationHint': {
                'attributes': ['rawString']
            },
            'evaluateName': '__name__'
        }, {
            'name': '__package__',
            'type': 'NoneType',
            'value': 'None',
            'evaluateName': '__package__'
        }, {
            'name': '__spec__',
            'type': 'NoneType',
            'value': 'None',
            'evaluateName': '__spec__'
        }])
        self.assertEqual(var_a_evaluate, {
            'type': 'int',
            'result': '1',
        })

        assert var_b_variables is not None
        self.assert_is_subset(var_b_variables, [{
            'type': 'int',
            'value': '1',
            'evaluateName': "b['one']"
        }, {
            'type': 'int',
            'value': '2',
            'evaluateName': "b['two']"
        }, {
            'name': '__len__',
            'type': 'int',
            'value': '2',
            'evaluateName': 'b.__len__'
        }])

        self.assertEqual(var_b_one_evaluate, {
            'type': 'int',
            'result': '1',
        })