Skip to content

Commit

Permalink
Use a shared file-system lock in create_server (#11294)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
marxin and AA-Turner authored Apr 6, 2023
1 parent 9299003 commit a80e3fd
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ test = [
"pytest>=4.6",
"html5lib",
"cython",
"filelock"
]

[[project.authors]]
Expand Down
6 changes: 4 additions & 2 deletions tests/test_build_linkcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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]
Expand Down
22 changes: 15 additions & 7 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@
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):
Expand All @@ -34,12 +40,14 @@ def __init__(self, handler, *args, **kwargs):

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)


Expand Down

0 comments on commit a80e3fd

Please sign in to comment.