test: update integration tests for RESTful routes

This commit is contained in:
qzl
2026-02-26 14:08:10 +08:00
parent 3cab7b03f7
commit 2709d88c68
5 changed files with 360 additions and 384 deletions
+110 -112
View File
@@ -10,19 +10,18 @@ from fastapi.testclient import TestClient
from app import app
from core.auth.models import CurrentUser
from v1.auth.dependencies import get_auth_service
from v1.profile.dependencies import get_current_user
from v1.users.dependencies import get_current_user
from v1.auth.rate_limit import reset_rate_limit_state
from v1.auth.schemas import (
AuthResendCodeResponse,
AuthSignupStartResponse,
AuthTokenResponse,
AuthUserByEmailResponse,
AuthUser,
LoginRequest,
RefreshRequest,
SignupResendRequest,
SignupStartRequest,
SignupVerifyRequest,
SessionCreateRequest,
SessionRefreshRequest,
SessionResponse,
UserByEmailResponse,
VerificationCreateRequest,
VerificationCreateResponse,
VerificationResendRequest,
VerificationVerifyRequest,
)
from v1.auth.service import AuthService
@@ -33,39 +32,39 @@ def reset_auth_rate_limit_state() -> None:
class FakeAuthService(AuthService):
def __init__(self, token_response: AuthTokenResponse) -> None:
def __init__(self, token_response: SessionResponse) -> None:
self._token_response = token_response
async def signup_start(
self, request: SignupStartRequest
) -> AuthSignupStartResponse:
async def create_verification(
self, request: VerificationCreateRequest
) -> VerificationCreateResponse:
if request.email == "exists@example.com":
raise HTTPException(status_code=422, detail="Invalid signup request")
return AuthSignupStartResponse(email=request.email)
return VerificationCreateResponse(email=request.email)
async def signup_verify(self, request: SignupVerifyRequest) -> AuthTokenResponse:
async def verify_verification(
self, request: VerificationVerifyRequest
) -> SessionResponse:
if request.token == "000000":
raise HTTPException(status_code=401, detail="Invalid verification code")
return self._token_response
async def signup_resend(
self, request: SignupResendRequest
) -> AuthResendCodeResponse:
return AuthResendCodeResponse()
async def login(self, request: LoginRequest) -> AuthTokenResponse:
raise HTTPException(status_code=401, detail="Invalid credentials")
async def refresh(self, request: RefreshRequest) -> AuthTokenResponse:
raise HTTPException(status_code=401, detail="Invalid refresh token")
async def logout(self, refresh_token: str | None) -> None:
async def resend_verification(self, request: VerificationResendRequest) -> None:
return None
async def get_user_by_email(self, email: str) -> AuthUserByEmailResponse:
async def create_session(self, request: SessionCreateRequest) -> SessionResponse:
raise HTTPException(status_code=401, detail="Invalid credentials")
async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse:
raise HTTPException(status_code=401, detail="Invalid refresh token")
async def delete_session(self, refresh_token: str | None) -> None:
return None
async def get_user_by_email(self, email: str) -> UserByEmailResponse:
if email == "missing@example.com":
raise HTTPException(status_code=404, detail="User not found")
return AuthUserByEmailResponse(
return UserByEmailResponse(
id="user-1",
email=email,
created_at="2026-02-24T00:00:00Z",
@@ -82,7 +81,7 @@ def _override_auth_service(service: AuthService) -> Callable[[], AuthService]:
def test_signup_start_returns_pending_response() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -96,7 +95,7 @@ def test_signup_start_returns_pending_response() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/signup/start",
"/api/v1/auth/verifications",
json={
"username": "demo",
"email": "user@example.com",
@@ -105,7 +104,6 @@ def test_signup_start_returns_pending_response() -> None:
)
assert response.status_code == 202
body = response.json()
assert body["status"] == "pending_verification"
assert body["email"] == "user@example.com"
finally:
app.dependency_overrides = {}
@@ -113,7 +111,7 @@ def test_signup_start_returns_pending_response() -> None:
def test_signup_verify_returns_token_response() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -127,7 +125,7 @@ def test_signup_verify_returns_token_response() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/signup/verify",
"/api/v1/auth/verifications/verify",
json={"email": "user@example.com", "token": "123456"},
)
assert response.status_code == 200
@@ -141,7 +139,7 @@ def test_signup_verify_returns_token_response() -> None:
def test_signup_resend_returns_generic_message() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -155,21 +153,18 @@ def test_signup_resend_returns_generic_message() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/signup/resend",
"/api/v1/auth/verifications/resend",
json={"email": "user@example.com"},
)
assert response.status_code == 200
body = response.json()
assert (
body["message"] == "If the email exists, a verification code has been sent"
)
assert response.status_code == 204
assert response.content == b""
finally:
app.dependency_overrides = {}
def test_signup_verify_invalid_token_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -183,7 +178,7 @@ def test_signup_verify_invalid_token_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/signup/verify",
"/api/v1/auth/verifications/verify",
json={"email": "user@example.com", "token": "000000"},
)
assert response.status_code == 401
@@ -198,7 +193,7 @@ def test_signup_verify_invalid_token_returns_problem_details() -> None:
def test_signup_start_existing_email_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -212,7 +207,7 @@ def test_signup_start_existing_email_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/signup/start",
"/api/v1/auth/verifications",
json={
"username": "demo",
"email": "exists@example.com",
@@ -231,7 +226,7 @@ def test_signup_start_existing_email_returns_problem_details() -> None:
def test_signup_verify_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -246,13 +241,13 @@ def test_signup_verify_rate_limited_after_too_many_attempts() -> None:
try:
for _ in range(10):
ok = client.post(
"/api/v1/auth/signup/verify",
"/api/v1/auth/verifications/verify",
json={"email": "user@example.com", "token": "123456"},
)
assert ok.status_code == 200
blocked = client.post(
"/api/v1/auth/signup/verify",
"/api/v1/auth/verifications/verify",
json={"email": "user@example.com", "token": "123456"},
)
assert blocked.status_code == 429
@@ -263,39 +258,7 @@ def test_signup_verify_rate_limited_after_too_many_attempts() -> None:
def test_signup_resend_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
token_type="bearer",
user=user,
)
app.dependency_overrides[get_auth_service] = _override_auth_service(
FakeAuthService(token_response)
)
client = TestClient(app)
try:
for _ in range(3):
ok = client.post(
"/api/v1/auth/signup/resend",
json={"email": "user@example.com"},
)
assert ok.status_code == 200
blocked = client.post(
"/api/v1/auth/signup/resend",
json={"email": "user@example.com"},
)
assert blocked.status_code == 429
assert blocked.headers["content-type"].startswith("application/problem+json")
finally:
app.dependency_overrides = {}
def test_signup_start_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -310,7 +273,39 @@ def test_signup_start_rate_limited_after_too_many_attempts() -> None:
try:
for _ in range(5):
ok = client.post(
"/api/v1/auth/signup/start",
"/api/v1/auth/verifications/resend",
json={"email": "user@example.com"},
)
assert ok.status_code == 204
blocked = client.post(
"/api/v1/auth/verifications/resend",
json={"email": "user@example.com"},
)
assert blocked.status_code == 429
assert blocked.headers["content-type"].startswith("application/problem+json")
finally:
app.dependency_overrides = {}
def test_signup_start_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
token_type="bearer",
user=user,
)
app.dependency_overrides[get_auth_service] = _override_auth_service(
FakeAuthService(token_response)
)
client = TestClient(app)
try:
for _ in range(5):
ok = client.post(
"/api/v1/auth/verifications",
json={
"username": "demo",
"email": "user@example.com",
@@ -320,7 +315,7 @@ def test_signup_start_rate_limited_after_too_many_attempts() -> None:
assert ok.status_code == 202
blocked = client.post(
"/api/v1/auth/signup/start",
"/api/v1/auth/verifications",
json={
"username": "demo",
"email": "user@example.com",
@@ -335,7 +330,7 @@ def test_signup_start_rate_limited_after_too_many_attempts() -> None:
def test_login_invalid_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -349,7 +344,7 @@ def test_login_invalid_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/login",
"/api/v1/auth/sessions",
json={"email": "user@example.com", "password": "wrongpw"},
)
assert response.status_code == 401
@@ -364,7 +359,7 @@ def test_login_invalid_returns_problem_details() -> None:
def test_refresh_invalid_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -378,7 +373,7 @@ def test_refresh_invalid_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/refresh",
"/api/v1/auth/sessions/refresh",
json={"refresh_token": "invalid"},
)
assert response.status_code == 401
@@ -393,7 +388,7 @@ def test_refresh_invalid_returns_problem_details() -> None:
def test_logout_returns_no_content() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -406,8 +401,9 @@ def test_logout_returns_no_content() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/logout",
response = client.request(
"DELETE",
"/api/v1/auth/sessions",
json={"refresh_token": "refresh"},
)
assert response.status_code == 204
@@ -418,7 +414,7 @@ def test_logout_returns_no_content() -> None:
def test_login_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -433,13 +429,13 @@ def test_login_rate_limited_after_too_many_attempts() -> None:
try:
for _ in range(10):
blocked = client.post(
"/api/v1/auth/login",
"/api/v1/auth/sessions",
json={"email": "user@example.com", "password": "wrongpw"},
)
assert blocked.status_code == 401
blocked = client.post(
"/api/v1/auth/login",
"/api/v1/auth/sessions",
json={"email": "user@example.com", "password": "wrongpw"},
)
assert blocked.status_code == 429
@@ -452,7 +448,7 @@ def test_login_rate_limited_after_too_many_attempts() -> None:
def test_refresh_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -467,13 +463,13 @@ def test_refresh_rate_limited_after_too_many_attempts() -> None:
try:
for _ in range(10):
blocked = client.post(
"/api/v1/auth/refresh",
"/api/v1/auth/sessions/refresh",
json={"refresh_token": "invalid"},
)
assert blocked.status_code == 401
blocked = client.post(
"/api/v1/auth/refresh",
"/api/v1/auth/sessions/refresh",
json={"refresh_token": "invalid"},
)
assert blocked.status_code == 429
@@ -486,7 +482,7 @@ def test_refresh_rate_limited_after_too_many_attempts() -> None:
def test_logout_rate_limited_after_too_many_attempts() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -500,14 +496,16 @@ def test_logout_rate_limited_after_too_many_attempts() -> None:
client = TestClient(app)
try:
for _ in range(10):
ok = client.post(
"/api/v1/auth/logout",
ok = client.request(
"DELETE",
"/api/v1/auth/sessions",
json={"refresh_token": "refresh"},
)
assert ok.status_code == 204
blocked = client.post(
"/api/v1/auth/logout",
blocked = client.request(
"DELETE",
"/api/v1/auth/sessions",
json={"refresh_token": "refresh"},
)
assert blocked.status_code == 429
@@ -520,7 +518,7 @@ def test_logout_rate_limited_after_too_many_attempts() -> None:
def test_signup_start_validation_error_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -533,7 +531,7 @@ def test_signup_start_validation_error_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.post("/api/v1/auth/signup/start", json={})
response = client.post("/api/v1/auth/verifications", json={})
assert response.status_code == 422
assert response.headers["content-type"].startswith("application/problem+json")
body = response.json()
@@ -546,7 +544,7 @@ def test_signup_start_validation_error_returns_problem_details() -> None:
def test_signup_start_missing_username_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -560,7 +558,7 @@ def test_signup_start_missing_username_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.post(
"/api/v1/auth/signup/start",
"/api/v1/auth/verifications",
json={"email": "user@example.com", "password": "secret123"},
)
assert response.status_code == 422
@@ -575,7 +573,7 @@ def test_signup_start_missing_username_returns_problem_details() -> None:
def test_get_user_by_email_returns_user() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -593,7 +591,7 @@ def test_get_user_by_email_returns_user() -> None:
client = TestClient(app)
try:
response = client.get(
"/api/v1/auth/users/by-email",
"/api/v1/auth/users",
params={"email": "user@example.com"},
)
assert response.status_code == 200
@@ -606,7 +604,7 @@ def test_get_user_by_email_returns_user() -> None:
def test_get_user_by_email_not_found_returns_problem_details() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -624,7 +622,7 @@ def test_get_user_by_email_not_found_returns_problem_details() -> None:
client = TestClient(app)
try:
response = client.get(
"/api/v1/auth/users/by-email",
"/api/v1/auth/users",
params={"email": "missing@example.com"},
)
assert response.status_code == 404
@@ -639,7 +637,7 @@ def test_get_user_by_email_not_found_returns_problem_details() -> None:
def test_get_user_by_email_forbidden_when_querying_other_user() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = AuthTokenResponse(
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
@@ -657,7 +655,7 @@ def test_get_user_by_email_forbidden_when_querying_other_user() -> None:
client = TestClient(app)
try:
response = client.get(
"/api/v1/auth/users/by-email",
"/api/v1/auth/users",
params={"email": "target@example.com"},
)
assert response.status_code == 403