Skip to content

Commit 54857ea

Browse files
CopilotP4X-ng
andcommitted
Add detachFromTarget call when closing session
- Modified open_session() to call detachFromTarget in a finally block - Added tests to verify detachFromTarget is called on normal exit and exception Co-authored-by: P4X-ng <223870169+P4X-ng@users.noreply.github.com>
1 parent 79c4080 commit 54857ea

2 files changed

Lines changed: 136 additions & 2 deletions

File tree

tests/test_session_detach.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
"""
2+
Test that detachFromTarget is called when closing a session.
3+
"""
4+
import json
5+
import logging
6+
import sys
7+
import os
8+
9+
# Add the source directory to path
10+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
11+
12+
from cdp import target
13+
import pytest
14+
import trio
15+
from trio_websocket import serve_websocket
16+
17+
# Import directly from the main module to avoid generated imports
18+
from trio_cdp import CdpConnection, open_cdp
19+
20+
# Import test utilities
21+
from . import fail_after
22+
23+
24+
HOST = '127.0.0.1'
25+
26+
27+
async def start_server(nursery, handler):
28+
''' A helper that starts a WebSocket server and runs ``handler`` for each
29+
connection. Returns the server URL. '''
30+
server = await nursery.start(serve_websocket, handler, HOST, 0, None)
31+
return f'ws://{HOST}:{server.port}/devtools/browser/uuid'
32+
33+
34+
@fail_after(5)
35+
async def test_session_detach_on_exit(nursery):
36+
"""Test that detachFromTarget is called when exiting open_session context."""
37+
detach_called = False
38+
39+
async def handler(request):
40+
nonlocal detach_called
41+
try:
42+
ws = await request.accept()
43+
44+
# Handle "attachToTarget" command
45+
command = json.loads(await ws.get_message())
46+
assert command['method'] == 'Target.attachToTarget'
47+
assert command['params']['targetId'] == 'target1'
48+
logging.info('Server received attachToTarget: %r', command)
49+
response = {
50+
'id': command['id'],
51+
'result': {
52+
'sessionId': 'session1',
53+
}
54+
}
55+
logging.info('Server sending: %r', response)
56+
await ws.send_message(json.dumps(response))
57+
58+
# Handle "detachFromTarget" command
59+
command = json.loads(await ws.get_message())
60+
assert command['method'] == 'Target.detachFromTarget'
61+
assert command['params']['sessionId'] == 'session1'
62+
detach_called = True
63+
logging.info('Server received detachFromTarget: %r', command)
64+
response = {
65+
'id': command['id'],
66+
'result': {}
67+
}
68+
logging.info('Server sending: %r', response)
69+
await ws.send_message(json.dumps(response))
70+
except Exception:
71+
logging.exception('Server exception')
72+
73+
server = await start_server(nursery, handler)
74+
75+
async with open_cdp(server) as conn:
76+
async with conn.open_session(target.TargetID('target1')) as session:
77+
assert session.session_id == 'session1'
78+
# Don't do anything else in the session
79+
80+
# After exiting the session context, detach should have been called
81+
assert detach_called, "detachFromTarget was not called when session closed"
82+
83+
84+
@fail_after(5)
85+
async def test_session_detach_on_exception(nursery):
86+
"""Test that detachFromTarget is called even when an exception occurs in the session."""
87+
detach_called = False
88+
89+
async def handler(request):
90+
nonlocal detach_called
91+
try:
92+
ws = await request.accept()
93+
94+
# Handle "attachToTarget" command
95+
command = json.loads(await ws.get_message())
96+
assert command['method'] == 'Target.attachToTarget'
97+
logging.info('Server received attachToTarget: %r', command)
98+
response = {
99+
'id': command['id'],
100+
'result': {
101+
'sessionId': 'session1',
102+
}
103+
}
104+
await ws.send_message(json.dumps(response))
105+
106+
# Handle "detachFromTarget" command
107+
command = json.loads(await ws.get_message())
108+
assert command['method'] == 'Target.detachFromTarget'
109+
assert command['params']['sessionId'] == 'session1'
110+
detach_called = True
111+
logging.info('Server received detachFromTarget: %r', command)
112+
response = {
113+
'id': command['id'],
114+
'result': {}
115+
}
116+
await ws.send_message(json.dumps(response))
117+
except Exception:
118+
logging.exception('Server exception')
119+
120+
server = await start_server(nursery, handler)
121+
122+
async with open_cdp(server) as conn:
123+
with pytest.raises(RuntimeError):
124+
async with conn.open_session(target.TargetID('target1')) as session:
125+
assert session.session_id == 'session1'
126+
# Raise an exception in the session
127+
raise RuntimeError("Test exception")
128+
129+
# After exiting the session context, detach should still have been called
130+
assert detach_called, "detachFromTarget was not called when session closed with exception"

trio_cdp/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,12 @@ async def open_session(self, target_id: cdp.target.TargetID) -> \
239239
and it will execute on the current session automatically.
240240
'''
241241
session = await self.connect_session(target_id)
242-
with session_context(session):
243-
yield session
242+
try:
243+
with session_context(session):
244+
yield session
245+
finally:
246+
await self.execute(cdp.target.detach_from_target(
247+
session.session_id, session.target_id))
244248

245249
async def connect_session(self, target_id: cdp.target.TargetID) -> 'CdpSession':
246250
'''

0 commit comments

Comments
 (0)