Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 91089d9

Browse files
committed
Use a random port for WebAgg tests
This prevents them from conflicting when run in parallel. Even though there is some attempt to pick alternative ports, that seems to cause a socket leak somewhere in Tornado, which Pytest converts to an error, so we have to do it manually. Also ensure the interactive WebAgg subprocess is actually killed.
1 parent 2fa87bb commit 91089d9

File tree

3 files changed

+34
-11
lines changed

3 files changed

+34
-11
lines changed

lib/matplotlib/tests/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,20 @@
1+
import contextlib
2+
import socket
3+
4+
import pytest
5+
16
from matplotlib.testing.conftest import ( # noqa
27
mpl_test_settings, pytest_configure, pytest_unconfigure, pd, xr)
8+
9+
10+
@pytest.fixture
11+
def random_port():
12+
with contextlib.closing(
13+
socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
14+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
15+
s.bind(('', 0))
16+
s.listen(1)
17+
addr = s.getsockname()
18+
port = addr[1]
19+
20+
return port

lib/matplotlib/tests/test_backend_webagg.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ def test_webagg_core_no_toolbar():
5252

5353

5454
@pytest.mark.backend('webagg')
55-
def test_webagg_general(page):
55+
def test_webagg_general(random_port, page):
5656
from playwright.sync_api import expect
5757

5858
fig, ax = plt.subplots(facecolor='w')
5959

6060
# Don't start the Tornado event loop, but use the existing event loop
6161
# started by the `page` fixture.
62-
WebAggApplication.initialize()
62+
WebAggApplication.initialize(port=random_port)
6363
WebAggApplication.started = True
6464

6565
page.goto(f'http://{WebAggApplication.address}:{WebAggApplication.port}/')
@@ -85,7 +85,7 @@ def test_webagg_general(page):
8585

8686
@pytest.mark.backend('webagg')
8787
@pytest.mark.parametrize('toolbar', ['toolbar2', 'toolmanager'])
88-
def test_webagg_toolbar(page, toolbar):
88+
def test_webagg_toolbar(random_port, page, toolbar):
8989
from playwright.sync_api import expect
9090

9191
with warnings.catch_warnings():
@@ -97,7 +97,7 @@ def test_webagg_toolbar(page, toolbar):
9797

9898
# Don't start the Tornado event loop, but use the existing event loop
9999
# started by the `page` fixture.
100-
WebAggApplication.initialize()
100+
WebAggApplication.initialize(port=random_port)
101101
WebAggApplication.started = True
102102

103103
page.goto(f'http://{WebAggApplication.address}:{WebAggApplication.port}/')
@@ -143,14 +143,14 @@ def test_webagg_toolbar(page, toolbar):
143143

144144

145145
@pytest.mark.backend('webagg')
146-
def test_webagg_toolbar_save(page):
146+
def test_webagg_toolbar_save(random_port, page):
147147
from playwright.sync_api import expect
148148

149149
fig, ax = plt.subplots(facecolor='w')
150150

151151
# Don't start the Tornado event loop, but use the existing event loop
152152
# started by the `page` fixture.
153-
WebAggApplication.initialize()
153+
WebAggApplication.initialize(port=random_port)
154154
WebAggApplication.started = True
155155

156156
page.goto(f'http://{WebAggApplication.address}:{WebAggApplication.port}/')

lib/matplotlib/tests/test_backends_interactive.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,15 +371,15 @@ def test_cross_Qt_imports():
371371
@pytest.mark.skipif('TF_BUILD' in os.environ,
372372
reason="this test fails an azure for unknown reasons")
373373
@pytest.mark.skipif(os.name == "nt", reason="Cannot send SIGINT on Windows.")
374-
def test_webagg():
374+
def test_webagg(random_port):
375375
pytest.importorskip("tornado")
376376
proc = subprocess.Popen(
377377
[sys.executable, "-c",
378378
inspect.getsource(_test_interactive_impl)
379-
+ "\n_test_interactive_impl()", "{}"],
379+
+ "\n_test_interactive_impl()",
380+
json.dumps({'webagg.port': random_port})],
380381
env={**os.environ, "MPLBACKEND": "webagg", "SOURCE_DATE_EPOCH": "0"})
381-
url = "http://{}:{}".format(
382-
mpl.rcParams["webagg.address"], mpl.rcParams["webagg.port"])
382+
url = f'http://{mpl.rcParams["webagg.address"]}:{random_port}'
383383
timeout = time.perf_counter() + _test_timeout
384384
while True:
385385
try:
@@ -395,7 +395,12 @@ def test_webagg():
395395
continue
396396
conn.close()
397397
proc.send_signal(signal.SIGINT)
398-
assert proc.wait(timeout=_test_timeout) == 0
398+
try:
399+
assert proc.wait(timeout=_test_timeout) == 0
400+
except subprocess.TimeoutExpired:
401+
proc.kill()
402+
proc.wait(timeout=_test_timeout)
403+
raise
399404

400405

401406
def _lazy_headless():

0 commit comments

Comments
 (0)