mirror of
https://github.com/simonw/datasette.git
synced 2026-06-15 13:36:58 +02:00
fix: resolve actual port before printing --root URL when -p 0
Closes #873. When `datasette -p 0 --root` was used, the printed auth-token URL contained the literal placeholder port 0 instead of the OS-assigned port that uvicorn would later bind to. Same applied to `--open`. Fix: when `port == 0` and we need to print/open a URL before the server starts (because of --root or --open), pre-bind a TCP socket on (host, 0), read the assigned port via getsockname(), and hand the bound socket to uvicorn via Server.run(sockets=[...]). uvicorn.run()'s own `fd=` parameter assumes AF_UNIX so we use the Config/Server API in this branch only; the existing uvicorn.run() path is unchanged. Adds a regression test that launches `datasette --memory -p 0 --root`, parses the printed URL, asserts the port is non-zero, and confirms a server is actually listening on that port.
This commit is contained in:
parent
0dc7bb19d9
commit
300fe125c5
2 changed files with 87 additions and 0 deletions
|
|
@ -1,6 +1,11 @@
|
|||
import httpx
|
||||
import pytest
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
|
||||
@pytest.mark.serial
|
||||
|
|
@ -27,3 +32,59 @@ def test_serve_unix_domain_socket(ds_unix_domain_socket_server):
|
|||
"path": "/_memory",
|
||||
"tables": [],
|
||||
}.items() <= response.json().items()
|
||||
|
||||
|
||||
@pytest.mark.serial
|
||||
def test_serve_root_url_uses_actual_port_when_port_is_zero():
|
||||
# Regression test for https://github.com/simonw/datasette/issues/873
|
||||
# `datasette -p 0 --root` printed http://127.0.0.1:0/... instead of
|
||||
# the OS-assigned port.
|
||||
proc = subprocess.Popen(
|
||||
[sys.executable, "-m", "datasette", "--memory", "-p", "0", "--root"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=tempfile.gettempdir(),
|
||||
text=True,
|
||||
)
|
||||
try:
|
||||
# Read lines until we see the auth-token URL or time out
|
||||
url_line = None
|
||||
deadline = time.time() + 10.0
|
||||
while time.time() < deadline:
|
||||
line = proc.stdout.readline()
|
||||
if not line:
|
||||
if proc.poll() is not None:
|
||||
break
|
||||
continue
|
||||
if "/-/auth-token?token=" in line:
|
||||
url_line = line.strip()
|
||||
break
|
||||
assert url_line, "Did not see auth-token URL in datasette output"
|
||||
match = re.match(r"http://127\.0\.0\.1:(\d+)/-/auth-token\?token=", url_line)
|
||||
assert match, f"Unexpected auth-token URL format: {url_line!r}"
|
||||
printed_port = int(match.group(1))
|
||||
assert printed_port != 0, (
|
||||
"datasette -p 0 --root should print the OS-assigned port, "
|
||||
"not the placeholder 0"
|
||||
)
|
||||
# Confirm a server is actually listening on that printed port
|
||||
deadline2 = time.time() + 5.0
|
||||
last_err = None
|
||||
while time.time() < deadline2:
|
||||
try:
|
||||
response = httpx.get(f"http://127.0.0.1:{printed_port}/_memory.json")
|
||||
assert response.status_code == 200
|
||||
break
|
||||
except httpx.ConnectError as exc:
|
||||
last_err = exc
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
raise AssertionError(
|
||||
f"Could not connect to printed port {printed_port}: {last_err}"
|
||||
)
|
||||
finally:
|
||||
proc.terminate()
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue