106 lines
2.9 KiB
Python
106 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import signal
|
|
import socket
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from admin_server import send_admin_command
|
|
|
|
pytestmark = pytest.mark.skipif(os.name == "nt", reason="SIGTERM integration is POSIX-only")
|
|
|
|
SERVER_DIR = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def _free_port() -> int:
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
sock.bind(("127.0.0.1", 0))
|
|
return int(sock.getsockname()[1])
|
|
|
|
|
|
def test_sigterm_exits_cleanly(tmp_path: Path) -> None:
|
|
game_port = _free_port()
|
|
admin_port = _free_port()
|
|
config_path = tmp_path / "commonwealth-server.json"
|
|
config_path.write_text(
|
|
json.dumps(
|
|
{
|
|
"host": "127.0.0.1",
|
|
"port": game_port,
|
|
"server_name": "CI Test Server",
|
|
"server_description": "",
|
|
"max_players": 4,
|
|
"log_verbosity": "info",
|
|
"admin_port": admin_port,
|
|
},
|
|
indent=2,
|
|
)
|
|
+ "\n",
|
|
encoding="utf-8",
|
|
newline="\n",
|
|
)
|
|
|
|
env = os.environ.copy()
|
|
env["PYTHONUNBUFFERED"] = "1"
|
|
env["NO_COLOR"] = "1"
|
|
|
|
process = subprocess.Popen(
|
|
[
|
|
sys.executable,
|
|
"-u",
|
|
str(SERVER_DIR / "consumer_server_cli.py"),
|
|
"serve",
|
|
"--config",
|
|
str(config_path),
|
|
],
|
|
cwd=str(SERVER_DIR),
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
env=env,
|
|
)
|
|
|
|
try:
|
|
deadline = time.time() + 10.0
|
|
connected = False
|
|
while time.time() < deadline:
|
|
try:
|
|
with socket.create_connection(("127.0.0.1", game_port), timeout=0.5) as conn:
|
|
welcome = conn.recv(4096)
|
|
if b"welcome" in welcome:
|
|
connected = True
|
|
break
|
|
except OSError:
|
|
time.sleep(0.1)
|
|
assert connected, "server did not accept a test client in time"
|
|
|
|
admin_deadline = time.time() + 5.0
|
|
response: dict[str, object] | None = None
|
|
while time.time() < admin_deadline:
|
|
try:
|
|
response = send_admin_command({"cmd": "ping"}, port=admin_port, timeout_seconds=0.5)
|
|
break
|
|
except (OSError, RuntimeError, ConnectionError):
|
|
time.sleep(0.05)
|
|
assert response is not None
|
|
assert response.get("ok") is True
|
|
|
|
process.send_signal(signal.SIGTERM)
|
|
try:
|
|
exit_code = process.wait(timeout=10.0)
|
|
except subprocess.TimeoutExpired:
|
|
process.kill()
|
|
pytest.fail("server did not exit after SIGTERM")
|
|
|
|
assert exit_code == 0
|
|
finally:
|
|
if process.poll() is None:
|
|
process.kill()
|
|
process.wait(timeout=5.0)
|