Files
fangke/server/tracker/tests/test_auth.py
T
2026-09-15 14:18:37 +08:00

129 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import pytest
from django.contrib.auth import get_user_model
from django.core.cache import cache
from rest_framework.test import APIClient
pytestmark = pytest.mark.django_db
User = get_user_model()
@pytest.fixture(autouse=True)
def _clear_cache():
cache.clear() # locmem 限流历史跨测试残留,会让 429 用例假红(同 test_collect 模式)
@pytest.fixture
def client(): # 覆盖 pytest-django 的 Django Client——登录用例需要 credentials()/format="json"
return APIClient()
@pytest.fixture
def admin_user():
return User.objects.create_user(username="admin", password="adminpass123", is_staff=True)
def _auth(client, user):
from rest_framework_simplejwt.tokens import RefreshToken
token = RefreshToken.for_user(user)
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token.access_token}")
def test_login_ok_returns_tokens(client, admin_user):
r = client.post("/api/admin/auth/token",
{"username": "admin", "password": "adminpass123"}, format="json")
assert r.status_code == 200
body = r.json()
assert body["code"] == 200 and body["data"]["access"] and body["data"]["refresh"]
def test_login_wrong_password_401_envelope(client, admin_user):
"""simplejwt 失败默认 {detail} 无信封——同 Task7 经验,finalize_response 统一转
{code,data,message},管理台前端(Task17)按信封对接。"""
r = client.post("/api/admin/auth/token",
{"username": "admin", "password": "wrongpass"}, format="json")
assert r.status_code == 401
body = r.json()
assert body["code"] == 401 and body["data"] is None and body["message"]
def test_refresh_returns_new_access(client, admin_user):
from rest_framework_simplejwt.tokens import RefreshToken
refresh = RefreshToken.for_user(admin_user)
r = client.post("/api/admin/auth/refresh", {"refresh": str(refresh)}, format="json")
assert r.status_code == 200
body = r.json()
assert body["code"] == 200 and body["data"]["access"]
def test_me_requires_auth_envelope(client):
r = client.get("/api/admin/auth/me")
assert r.status_code == 401
assert r.json()["code"] == 401 # 无 token 的 401 同样走信封
def test_me_returns_username_and_flag(client, admin_user):
_auth(client, admin_user)
r = client.get("/api/admin/auth/me")
assert r.json()["data"] == {"username": "admin", "is_admin": True}
def test_user_create_admin_only(client, admin_user):
member = User.objects.create_user(username="member", password="memberpass123")
_auth(client, member)
r = client.post("/api/admin/users",
{"username": "newbie", "password": "longenough1"}, format="json")
assert r.status_code == 403
_auth(client, admin_user)
r = client.post("/api/admin/users",
{"username": "newbie", "password": "longenough1"}, format="json")
assert r.status_code == 200 and User.objects.filter(username="newbie", is_staff=False).exists()
def test_user_create_validates_input(client, admin_user):
_auth(client, admin_user)
assert client.post("/api/admin/users",
{"username": "x", "password": "short"}, format="json").status_code == 400
assert client.post("/api/admin/users",
{"username": "admin", "password": "longenough1"}, format="json").status_code == 409
# ---- 审查修复锁定测试 ----
def test_user_create_malformed_body_400_not_500(client, admin_user):
"""探针证实:JSON 数组 body / 非字符串 username/password 直接 500——入口统一 400 invalid_input。"""
_auth(client, admin_user)
assert client.post("/api/admin/users", ["arr"], format="json").status_code == 400
assert client.post("/api/admin/users",
{"username": 123, "password": "longenough1"}, format="json").status_code == 400
assert client.post("/api/admin/users",
{"username": "okname", "password": 12345678}, format="json").status_code == 400
def test_login_missing_password_field_envelope(client, admin_user):
"""simplejwt 缺 password 的 400 是 {"password":[...]} 字段校验形状——信封统一,前端单条解析路径。"""
r = client.post("/api/admin/auth/token", {"username": "admin"}, format="json")
assert r.status_code == 400
body = r.json()
assert body["code"] == 400 and body["message"] == "invalid_input" and body["data"]
def test_user_create_username_charset_and_length(client, admin_user):
"""字符集对齐 UnicodeUsernameValidator(create_user 不跑校验器);>150 防 MySQL DataError(sqlite 不报错须入口拦)。"""
_auth(client, admin_user)
assert client.post("/api/admin/users",
{"username": "bad name", "password": "longenough1"}, format="json").status_code == 400
assert client.post("/api/admin/users",
{"username": "x" * 151, "password": "longenough1"}, format="json").status_code == 400
assert client.post("/api/admin/users",
{"username": "ok.name+1", "password": "longenough1"}, format="json").status_code == 200
def test_login_throttle_429_envelope(client, admin_user):
"""直接打默认 10/min(THROTTLE_RATES import 时固化为类属性,override_settings 提速无效,
同 collect.py CollectThrottle.get_rate 注释)——第 11 次 429 且带信封。"""
for _ in range(10):
assert client.post("/api/admin/auth/token",
{"username": "admin", "password": "wrongpass"}, format="json").status_code == 401
r = client.post("/api/admin/auth/token",
{"username": "admin", "password": "wrongpass"}, format="json")
assert r.status_code == 429
body = r.json()
assert body["code"] == 429 and body["data"] is None and body["message"]