v1.5.4: test infrastructure + bug fixes + CI/CD + deploy gate
- 6 new test files: route discovery, strict permissions, role switch, CRUD operations, 500 error protection - permission_config.py: central permission definitions for all 110+ routes - Bug fixes: is_active checkbox in users_edit, int(id) 500 crash, missing validation in users_create/users_delete - Pre-commit hooks: lint + static routing tests - GitHub Actions CI: full pytest suite on push - Deploy gate: pytest runs before deploy, aborts on failure - All 3 deploy scripts: --skip-tests flag support
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
"""Strict permission tests — every role × every route with exact expected codes.
|
||||
|
||||
ALLOWED → status must be 200 or 302 (never 403/404/500)
|
||||
DENIED → status must be 403 (strict — not 302!)
|
||||
ANONYMOUS → protected routes get 302 (redirect to login)
|
||||
→ public routes get 200
|
||||
|
||||
Dynamic routes (with path params like {slug}) are skipped here.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from tests.permission_config import ROUTE_PERMISSIONS, DYNAMIC_ROUTES, ROLES
|
||||
|
||||
|
||||
def _generate_test_cases():
|
||||
"""Yield (role, method, path, expected) tuples."""
|
||||
for (method, path), allowed_roles in ROUTE_PERMISSIONS.items():
|
||||
if (method, path) in DYNAMIC_ROUTES:
|
||||
continue
|
||||
for role in ROLES:
|
||||
if role in allowed_roles or "authenticated" in allowed_roles:
|
||||
yield (role, method, path, "allow")
|
||||
else:
|
||||
yield (role, method, path, "deny")
|
||||
|
||||
# Anonymous
|
||||
if "anonymous" in allowed_roles:
|
||||
yield ("anonymous", method, path, "allow")
|
||||
else:
|
||||
yield ("anonymous", method, path, "deny")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("role,method,path,expected", list(_generate_test_cases()))
|
||||
def test_access(role_client, role, method, path, expected):
|
||||
client = role_client[role]
|
||||
resp = client.request(method, path)
|
||||
|
||||
if expected == "allow":
|
||||
assert resp.status_code not in (403, 404), (
|
||||
f"[{role}] {method} {path}: got {resp.status_code}, expected non-403/404"
|
||||
)
|
||||
if resp.status_code == 500:
|
||||
pytest.fail(f"[{role}] {method} {path}: 500 Internal Server Error")
|
||||
else:
|
||||
if role == "anonymous":
|
||||
assert resp.status_code in (302, 403), (
|
||||
f"[{role}] {method} {path}: got {resp.status_code}, expected 302/403"
|
||||
)
|
||||
else:
|
||||
assert resp.status_code == 403, (
|
||||
f"[{role}] {method} {path}: got {resp.status_code}, expected 403"
|
||||
)
|
||||
Reference in New Issue
Block a user