Skip to content

Commit 80d94f6

Browse files
committed
fix(magics): resolve socket leak in system tests by tracking dynamic credential requests
1 parent 3329de1 commit 80d94f6

1 file changed

Lines changed: 56 additions & 15 deletions

File tree

packages/bigquery-magics/tests/system/test_bigquery.py

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,77 @@
1414

1515
"""System tests for Jupyter/IPython connector."""
1616

17+
import contextlib
18+
import gc
1719
import re
20+
import time
1821

1922
import pandas
2023
import psutil
2124
from IPython.testing import globalipapp
2225
from IPython.utils import io
2326

2427

28+
@contextlib.contextmanager
29+
def patch_tracked_requests():
30+
"""Context manager to patch google-auth requests and track/close their HTTP sessions.
31+
32+
This prevents socket leaks in system tests that use Workload Identity or metadata server auth.
33+
"""
34+
import google.auth.transport.requests
35+
36+
original_init = google.auth.transport.requests.Request.__init__
37+
tracked_requests = []
38+
39+
def patched_init(self, session=None):
40+
original_init(self, session=session)
41+
if session is None:
42+
tracked_requests.append(self)
43+
44+
google.auth.transport.requests.Request.__init__ = patched_init
45+
try:
46+
yield tracked_requests
47+
finally:
48+
google.auth.transport.requests.Request.__init__ = original_init
49+
for req in tracked_requests:
50+
if hasattr(req, "session") and req.session is not None:
51+
req.session.close()
52+
53+
2554
def test_bigquery_magic():
2655
globalipapp.start_ipython()
2756
ip = globalipapp.get_ipython()
2857
current_process = psutil.Process()
58+
59+
# GC to ensure clean starting state
60+
gc.collect()
2961
conn_count_start = len(current_process.net_connections())
3062

31-
ip.extension_manager.load_extension("bigquery_magics")
32-
sql = """
33-
SELECT
34-
CONCAT(
35-
'https://stackoverflow.com/questions/',
36-
CAST(id as STRING)) as url,
37-
view_count
38-
FROM `bigquery-public-data.stackoverflow.posts_questions`
39-
WHERE tags like '%google-bigquery%'
40-
ORDER BY view_count DESC
41-
LIMIT 10
42-
"""
43-
with io.capture_output() as captured:
44-
result = ip.run_cell_magic("bigquery", "--use_rest_api", sql)
63+
with patch_tracked_requests():
64+
ip.extension_manager.load_extension("bigquery_magics")
65+
sql = """
66+
SELECT
67+
CONCAT(
68+
'https://stackoverflow.com/questions/',
69+
CAST(id as STRING)) as url,
70+
view_count
71+
FROM `bigquery-public-data.stackoverflow.posts_questions`
72+
WHERE tags like '%google-bigquery%'
73+
ORDER BY view_count DESC
74+
LIMIT 10
75+
"""
76+
with io.capture_output() as captured:
77+
result = ip.run_cell_magic("bigquery", "--use_rest_api", sql)
78+
79+
# Force garbage collection to sweep unreferenced socket objects
80+
gc.collect()
4581

46-
conn_count_end = len(current_process.net_connections())
82+
# Wait a bit for the asynchronous channel teardown to complete and the socket to be closed.
83+
for _ in range(30):
84+
conn_count_end = len(current_process.net_connections())
85+
if conn_count_end <= conn_count_start:
86+
break
87+
time.sleep(0.1)
4788

4889
lines = re.split("\n|\r", captured.stdout)
4990
# Removes blanks & terminal code (result of display clearing)

0 commit comments

Comments
 (0)