152 lines
5.1 KiB
Python
152 lines
5.1 KiB
Python
"""认证授权扩展测试。
|
|
|
|
测试用例:
|
|
- AUTH-004c: 空用户名登录
|
|
- AUTH-004d: 空密码登录
|
|
- AUTH-006c: Token 自动续期
|
|
- AUTH-012b: 微信登录无效 code
|
|
- AUTH-012c: 绑定 OpenID
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.auth
|
|
@pytest.mark.p1
|
|
class TestLoginValidation:
|
|
"""登录参数校验测试。"""
|
|
|
|
def test_empty_username(self, client):
|
|
"""AUTH-004c: 空用户名登录应失败。"""
|
|
resp = client.post("/api/auth/login", json={
|
|
"username": "",
|
|
"password": "admin123",
|
|
"role_type": "admin",
|
|
})
|
|
assert resp.status_code in (400, 401, 422)
|
|
|
|
def test_empty_password(self, client):
|
|
"""AUTH-004d: 空密码登录应失败。"""
|
|
resp = client.post("/api/auth/login", json={
|
|
"username": "admin01",
|
|
"password": "",
|
|
"role_type": "admin",
|
|
})
|
|
assert resp.status_code in (400, 401, 422)
|
|
|
|
def test_missing_role_type(self, client):
|
|
"""缺少 role_type 可能成功或失败(取决于 API 默认值)。"""
|
|
resp = client.post("/api/auth/login", json={
|
|
"username": "admin01",
|
|
"password": "admin123",
|
|
})
|
|
assert resp.status_code in (200, 400, 401, 422)
|
|
|
|
def test_invalid_role_type(self, client):
|
|
"""无效 role_type 应失败。"""
|
|
resp = client.post("/api/auth/login", json={
|
|
"username": "admin01",
|
|
"password": "admin123",
|
|
"role_type": "invalid_role",
|
|
})
|
|
assert resp.status_code in (400, 401, 403, 422)
|
|
|
|
|
|
@pytest.mark.auth
|
|
@pytest.mark.p1
|
|
class TestTokenManagement:
|
|
"""Token 管理测试。"""
|
|
|
|
def test_me_endpoint_returns_user_info(self, client, admin_headers):
|
|
"""AUTH-010/011: /me 返回用户信息、菜单、权限。"""
|
|
resp = client.get("/api/auth/me", headers=admin_headers)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "user_id" in data
|
|
assert "role_code" in data
|
|
|
|
def test_me_without_token(self, client):
|
|
"""无 token 访问 /me 应返回 401。"""
|
|
resp = client.get("/api/auth/me")
|
|
assert resp.status_code == 401
|
|
|
|
def test_me_with_invalid_token(self, client):
|
|
"""无效 token 访问 /me 应返回 401。"""
|
|
resp = client.get("/api/auth/me", headers={
|
|
"Authorization": "Bearer invalid_token_here",
|
|
})
|
|
assert resp.status_code == 401
|
|
|
|
def test_logout(self, client, admin_headers):
|
|
"""登出成功。"""
|
|
resp = client.post("/api/auth/logout", headers=admin_headers)
|
|
assert resp.status_code == 200
|
|
|
|
def test_token_after_logout(self, client, admin_headers):
|
|
"""登出后 token 应失效。"""
|
|
# 先登出
|
|
client.post("/api/auth/logout", headers=admin_headers)
|
|
# 再用同一 token 访问
|
|
resp = client.get("/api/auth/me", headers=admin_headers)
|
|
assert resp.status_code == 401
|
|
|
|
|
|
@pytest.mark.auth
|
|
@pytest.mark.p1
|
|
class TestWeChatAuth:
|
|
"""微信登录测试。"""
|
|
|
|
def test_wechat_login_invalid_code(self, client):
|
|
"""AUTH-012b: 微信登录无效 code。"""
|
|
resp = client.post("/api/auth/wechat-login", json={
|
|
"code": "invalid_wx_code",
|
|
})
|
|
assert resp.status_code in (400, 401, 422, 500)
|
|
|
|
def test_bind_openid(self, client, admin_headers):
|
|
"""AUTH-012c: 绑定 OpenID。"""
|
|
resp = client.post("/api/auth/bind-openid", headers=admin_headers, json={
|
|
"open_id": "test_open_id_123",
|
|
})
|
|
assert resp.status_code in (200, 400, 422)
|
|
|
|
|
|
@pytest.mark.auth
|
|
@pytest.mark.p1
|
|
class TestRolePermissionBoundary:
|
|
"""角色权限边界测试。"""
|
|
|
|
def test_all_roles_can_login(self, client):
|
|
"""所有角色都能正常登录。"""
|
|
accounts = [
|
|
("admin01", "admin123", "admin"),
|
|
("sales01", "sales123", "salesman"),
|
|
("manager01", "manager123", "manager"),
|
|
("driver01", "driver123", "driver"),
|
|
]
|
|
for username, password, role_type in accounts:
|
|
resp = client.post("/api/auth/login", json={
|
|
"username": username,
|
|
"password": password,
|
|
"role_type": role_type,
|
|
})
|
|
assert resp.status_code == 200, f"{username} login failed"
|
|
|
|
def test_driver_cannot_access_financial_data(self, client, driver_headers, make_order):
|
|
"""司机不能访问财务数据。"""
|
|
order = make_order()
|
|
resp = client.get(f"/api/orders/{order.id}", headers=driver_headers)
|
|
# 司机应被拒绝或看不到财务字段
|
|
assert resp.status_code in (200, 403)
|
|
|
|
def test_salesman_cannot_view_reports(self, client, salesman_headers):
|
|
"""业务员不能查看绩效报表。"""
|
|
resp = client.get("/api/reports/performance", headers=salesman_headers)
|
|
assert resp.status_code == 403
|
|
|
|
def test_driver_cannot_view_reports(self, client, driver_headers):
|
|
"""司机不能查看绩效报表。"""
|
|
resp = client.get("/api/reports/performance", headers=driver_headers)
|
|
assert resp.status_code == 403
|