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)
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)