multi-user auth (CLI-created accounts), per-user history, test suite
- server/users.py replaces credentials.py: users.json (0600), PBKDF2, one-time migration of the legacy single password to user admin (history.json -> history/admin.json) - accounts are CLI-managed only: python -m server.users add|rm|list (no self-signup on an internet-exposed app); /signup route removed, login page back to username + password - per-user 30-day signed session cookie (payload carries the username), per-user lockout, GET /api/me, POST /account/delete - per-user watch history: server/data/history/<user>.json; ANIWEB_DATA env override for the data dir - header chip: logged-in user, logout, delete account - tests/: throwaway-server suite (port 8399, temp data dir) — 9 HTTP tests + 2 Playwright browser tests (login UI, real video playback behind auth); runs via python tests/run.py
This commit is contained in:
1 parent
76c45a8f29
commit
c697500c7d
12 files changed
+595
-122
No files matched your search
@@ -0,0 +1,86 @@
|
||||
"""run.py — full ani-web test suite.
|
||||
|
||||
Spins up a throwaway server (127.0.0.1:8399, temp data dir, seeded
|
||||
users admin/alice/bob), runs the API tests and (if playwright is
|
||||
installed) the browser tests, then tears everything down. The real
|
||||
server on :8321 and its data are never touched.
|
||||
|
||||
Usage: .venv/bin/python tests/run.py
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
PORT = 8399
|
||||
BASE = f"http://127.0.0.1:{PORT}"
|
||||
USERS = (("admin", "adminpw12345"), ("alice", "alicepw12345"), ("bob", "bobpw12345"),
|
||||
("dave", "davepw12345"))
|
||||
|
||||
|
||||
def _wait_ready():
|
||||
for _ in range(120):
|
||||
try:
|
||||
urllib.request.urlopen(BASE + "/login", timeout=1)
|
||||
return
|
||||
except Exception:
|
||||
time.sleep(0.5)
|
||||
raise SystemExit("server did not start")
|
||||
|
||||
|
||||
def main():
|
||||
data = Path(tempfile.mkdtemp(prefix="aniweb-test-"))
|
||||
os.environ["ANIWEB_DATA"] = str(data)
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from server import users
|
||||
for name, pw in USERS:
|
||||
users.add(name, pw)
|
||||
(data / "history").mkdir()
|
||||
(data / "history" / "admin.json").write_text(json.dumps([
|
||||
{"title": "Seed Anime", "slug_id": "seed-1", "season_id": 1, "ep_id": "1",
|
||||
"lang": "eng", "ep": "1", "pos": 10.0, "t": time.time()}]))
|
||||
|
||||
proc = subprocess.Popen(
|
||||
[sys.executable, "-m", "uvicorn", "server.app:app",
|
||||
"--host", "127.0.0.1", "--port", str(PORT)],
|
||||
cwd=ROOT, env=os.environ,
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
try:
|
||||
_wait_ready()
|
||||
|
||||
import test_api # noqa: E402 (tests/ on sys.path via script dir)
|
||||
# order matters: lockout test locks bob in memory, run it last
|
||||
api_tests = [fn for n, fn in sorted(vars(test_api).items())
|
||||
if n.startswith("test_") and n != "test_lockout_per_user"]
|
||||
for fn in api_tests:
|
||||
print(f"ok api.{fn.__name__}")
|
||||
fn(BASE)
|
||||
print("ok api.test_lockout_per_user")
|
||||
test_api.test_lockout_per_user(BASE)
|
||||
|
||||
try:
|
||||
import test_browser
|
||||
except ImportError:
|
||||
print("SKIP browser tests (pip install playwright && playwright install chromium)")
|
||||
else:
|
||||
print("ok browser (playwright)")
|
||||
asyncio.run(test_browser.test_login_ui())
|
||||
asyncio.run(test_browser.test_video_plays_behind_auth())
|
||||
|
||||
print("ALL TESTS PASSED")
|
||||
finally:
|
||||
proc.terminate()
|
||||
proc.wait()
|
||||
shutil.rmtree(data, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user