The duplicate file names (advanced, agency, auth, compliance, costing, etc.) in both root and routers/ made imports ambiguous. Renamed root modules to pry_<name>.py so: from quality import X -> from pry_quality import X from routers.quality import router (unchanged) Also: - Renamed x402.py to pry_x402/ package directory - Fixed 21+ bare imports across api.py, deps.py, routers/, tests/, llm_providers/ Tests: 593 passed, 1 skipped (test_ready_returns_200 fails pre-existing because Ollama is unreachable from test env, unrelated to this refactor). Audit item 8.
99 lines
2.7 KiB
Python
99 lines
2.7 KiB
Python
# SPDX-License-Identifier: MIT
|
|
# Copyright (c) 2026 Rug Munch Media LLC
|
|
#
|
|
# Part of Pry — https://git.rugmunch.io/RugMunchMedia/pryscraper
|
|
# Licensed under MIT. See LICENSE.
|
|
"""Tests for production infrastructure (auth, db, observability, jobs)."""
|
|
|
|
import asyncio
|
|
|
|
from pry_auth import AuthManager, base64_decode, base64_encode
|
|
from db import _has_sqlalchemy, get_db
|
|
from observability import track_llm_call, track_request, track_scrape
|
|
from tasks import JobQueue, JobStatus
|
|
|
|
|
|
def test_auth_hash_password() -> None:
|
|
a = AuthManager()
|
|
h, salt = a.hash_password("hunter2")
|
|
assert a.verify_password("hunter2", h, salt) is True
|
|
assert a.verify_password("wrong", h, salt) is False
|
|
|
|
|
|
def test_auth_api_key() -> None:
|
|
a = AuthManager()
|
|
user = a.create_user("test@example.com", "password")
|
|
key = a.create_api_key(user["id"])
|
|
assert key.startswith("pry_")
|
|
verified = a.verify_api_key(key)
|
|
assert verified is not None
|
|
assert verified["user_id"] == user["id"]
|
|
# Invalid key
|
|
assert a.verify_api_key("invalid") is None
|
|
|
|
|
|
def test_auth_rate_limit() -> None:
|
|
a = AuthManager()
|
|
a._rate_limits["test"] = {"window_start": 0, "count": 0}
|
|
allowed, remaining = a.check_rate_limit("test")
|
|
assert allowed is True
|
|
assert remaining >= 0
|
|
|
|
|
|
def test_auth_jwt_fallback() -> None:
|
|
a = AuthManager()
|
|
user = a.create_user("jwt@test.com", "pass")
|
|
token = a.create_jwt(user["id"])
|
|
payload = a.verify_jwt(token)
|
|
assert payload is not None
|
|
assert payload["sub"] == user["id"]
|
|
|
|
|
|
def test_base64_roundtrip() -> None:
|
|
assert base64_decode(base64_encode("hello world")) == "hello world"
|
|
|
|
|
|
def test_observability_track_request() -> None:
|
|
with track_request("/test"):
|
|
pass # Should not raise
|
|
|
|
|
|
def test_observability_track_scrape() -> None:
|
|
with track_scrape("direct"):
|
|
pass
|
|
|
|
|
|
def test_observability_track_llm() -> None:
|
|
track_llm_call("openai", "gpt-4o-mini", 0.001)
|
|
|
|
|
|
def test_db_is_available() -> None:
|
|
# Just check it doesn't crash; may be unavailable if no sqlalchemy
|
|
db = get_db()
|
|
if _has_sqlalchemy:
|
|
assert db is not None
|
|
|
|
|
|
def test_job_queue_submit() -> None:
|
|
async def _test():
|
|
q = JobQueue()
|
|
|
|
async def my_task(x):
|
|
return x * 2
|
|
|
|
job_id = await q.submit("double", my_task, args=(5,))
|
|
assert job_id in q.jobs
|
|
# Run inline
|
|
job = q.jobs[job_id]
|
|
await q._execute(job)
|
|
assert job.status == JobStatus.COMPLETED
|
|
assert job.result == 10
|
|
|
|
asyncio.run(_test())
|
|
|
|
|
|
def test_job_listing() -> None:
|
|
q = JobQueue()
|
|
q.jobs["test"] = type("J", (), {"to_dict": lambda self: {"id": "test", "name": "x"}})()
|
|
# Simple smoke test
|
|
assert hasattr(q, "list_jobs")
|