Use a shared file-system lock in `create_server` (#11294)

With parallel run of tests, one gets "Address already in use" errors
as all tests attempt to bind to the same port. Fix it with a shared
file-system lock.

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
Martin Liška
2023-04-06 23:24:49 +02:00
committed by GitHub
parent 9299003d40
commit a80e3fd377
3 changed files with 20 additions and 9 deletions

View File

@@ -93,6 +93,7 @@ test = [
"pytest>=4.6",
"html5lib",
"cython",
"filelock"
]
[[project.authors]]

View File

@@ -99,7 +99,8 @@ def test_defaults(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-too-many-retries', freshenv=True)
def test_too_many_retries(app):
app.build()
with http_server(DefaultsHandler):
app.build()
# Text output
assert (app.outdir / 'output.txt').exists()
@@ -688,7 +689,8 @@ def test_get_after_head_raises_connection_error(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-documents_exclude', freshenv=True)
def test_linkcheck_exclude_documents(app):
app.build()
with http_server(DefaultsHandler):
app.build()
with open(app.outdir / 'output.json', encoding='utf-8') as fp:
content = [json.loads(record) for record in fp]

View File

@@ -4,10 +4,16 @@ import pathlib
import threading
from ssl import PROTOCOL_TLS_SERVER, SSLContext
import filelock
# Generated with:
# $ openssl req -new -x509 -days 3650 -nodes -out cert.pem \
# -keyout cert.pem -addext "subjectAltName = DNS:localhost"
CERT_FILE = str(pathlib.Path(__file__).parent / "certs" / "cert.pem")
TESTS_ROOT = pathlib.Path(__file__).parent
CERT_FILE = str(TESTS_ROOT / "certs" / "cert.pem")
# File lock for tests
LOCK_PATH = str(TESTS_ROOT / 'test-server.lock')
class HttpServerThread(threading.Thread):
@@ -34,12 +40,14 @@ class HttpsServerThread(HttpServerThread):
def create_server(thread_class):
def server(handler):
server_thread = thread_class(handler, daemon=True)
server_thread.start()
try:
yield server_thread
finally:
server_thread.terminate()
lock = filelock.FileLock(LOCK_PATH)
with lock:
server_thread = thread_class(handler, daemon=True)
server_thread.start()
try:
yield server_thread
finally:
server_thread.terminate()
return contextlib.contextmanager(server)