def test_wait_for_attach(self):
        addr = Address('localhost', PORT)
        filename = self.write_script(
            'spam.py',
            """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output=False)

            ptvsd.wait_for_attach()
            # <ready>
            # <wait>
            """.format(PROJECT_ROOT, tuple(addr)),
        )
        lockfile1 = self.workspace.lockfile()
        _, wait = set_release(filename, lockfile1, 'ready')
        lockfile2 = self.workspace.lockfile()
        done, _ = set_lock(filename, lockfile2, 'wait')

        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter, timeout=1)
                # Ensure that it really does wait.
                with self.assertRaises(LockTimeoutError):
                    wait(timeout=0.5)

                lifecycle_handshake(session, 'attach')
                wait(timeout=1)
                done()
                adapter.wait()
    def test_does_not_block(self):
        addr = Address('localhost', PORT)
        filename = self.write_script('spam.py', """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output=False)
            # <ready>
            """.format(PROJECT_ROOT, tuple(addr)),
        )
        lockfile = self.workspace.lockfile()
        _, wait = set_release(filename, lockfile, 'ready')

        #DebugAdapter.VERBOSE = True
        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            wait(timeout=3)
            adapter.wait()
    def test_never_call_wait_for_attach(self):
        addr = Address('localhost', PORT)
        filename = self.write_script(
            'spam.py',
            """
            import sys
            import threading
            import time

            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output=False)
            # <ready>
            print('== ready ==')

            # Allow tracing to be triggered.
            def wait():
                # <wait>
                pass
            t = threading.Thread(target=wait)
            t.start()
            for _ in range(100):  # 10 seconds
                print('-----')
                t.join(0.1)
                if not t.is_alive():
                    break
            t.join()

            print('== starting ==')
            # <bp>
            print('== done ==')
            """.format(PROJECT_ROOT, tuple(addr)),
        )
        lockfile1 = self.workspace.lockfile('ready.lock')
        _, wait = set_release(filename, lockfile1, 'ready')
        lockfile2 = self.workspace.lockfile('wait.log')
        done, script = set_lock(filename, lockfile2, 'wait')

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

        #DebugAdapter.VERBOSE = True
        #DebugClient.SESSION.VERBOSE = True
        adapter = DebugAdapter.start_embedded(
            addr,
            filename,
            srvtimeout=None,
        )
        with adapter:
            # Wait longer that WAIT_TIMEOUT, so that debugging isn't
            # immediately enabled in the script's thread.
            wait(timeout=3.0)

            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter, timeout=1)
                stopped = session.get_awaiter_for_event('stopped')
                with session.wait_for_event('thread') as result:
                    lifecycle_handshake(session,
                                        'attach',
                                        breakpoints=breakpoints,
                                        threads=True)
                event = result['msg']
                tid = event.body['threadId']

                stopped.wait(timeout=5.0)
                done()
                session.send_request('continue', threadId=tid)

                adapter.wait()
        out = str(adapter.output)

        self.assertIn('== ready ==', out)
        self.assertIn('== starting ==', out)
Beispiel #4
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)