fix: expose actionable API error details
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
from django.test import Client
|
||||
from django.utils import timezone
|
||||
|
||||
from accounts.models import User
|
||||
from contest.models import Contest, ContestQuestion, Question, QuestionVersion
|
||||
from contest.models import (
|
||||
Contest,
|
||||
ContestQuestion,
|
||||
Question,
|
||||
QuestionVersion,
|
||||
RealtimeMatch,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -94,3 +103,103 @@ def test_challenge_api_创建加入状态提交形成完整闭环(realtime_api_s
|
||||
final_state = first_client.get(f"/api/v1/contests/matches/{match_id}/").json()
|
||||
assert final_state["result"]["winner"] == "self"
|
||||
assert final_state["attempt"]["questions"][0]["correct_answer"] == "42"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_challenge_api_无效联机码返回具体原因_request_id_和诊断日志(
|
||||
realtime_api_setup,
|
||||
caplog,
|
||||
):
|
||||
_, _, second_client = realtime_api_setup
|
||||
caplog.set_level("INFO", logger="common.api")
|
||||
|
||||
response = second_client.post(
|
||||
"/api/v1/contests/challenges/join/",
|
||||
{"challenge_code": "ABC234"},
|
||||
content_type="application/json",
|
||||
HTTP_X_REQUEST_ID="challenge-invalid-test",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response["X-Request-ID"] == "challenge-invalid-test"
|
||||
assert response.json()["error"] == {
|
||||
"code": "invalid",
|
||||
"message": "联机码不存在",
|
||||
"details": {"challenge_code": "联机码不存在"},
|
||||
"request_id": "challenge-invalid-test",
|
||||
}
|
||||
assert "api_request_error method=POST" in caplog.text
|
||||
assert "path=/api/v1/contests/challenges/join/" in caplog.text
|
||||
assert "fields=challenge_code message=联机码不存在" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_challenge_api_创建者不能加入自己的联机码(realtime_api_setup):
|
||||
contest, first_client, _ = realtime_api_setup
|
||||
created = first_client.post(
|
||||
f"/api/v1/contests/{contest.slug}/challenges/",
|
||||
{},
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
response = first_client.post(
|
||||
"/api/v1/contests/challenges/join/",
|
||||
{"challenge_code": created.json()["challenge_code"]},
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json()["error"]["message"] == "不能加入自己创建的约战"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_challenge_api_过期联机码返回具体原因(realtime_api_setup):
|
||||
contest, first_client, second_client = realtime_api_setup
|
||||
created = first_client.post(
|
||||
f"/api/v1/contests/{contest.slug}/challenges/",
|
||||
{},
|
||||
content_type="application/json",
|
||||
)
|
||||
RealtimeMatch.objects.filter(id=created.json()["match_id"]).update(
|
||||
expires_at=timezone.now() - timedelta(seconds=1)
|
||||
)
|
||||
|
||||
response = second_client.post(
|
||||
"/api/v1/contests/challenges/join/",
|
||||
{"challenge_code": created.json()["challenge_code"]},
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json()["error"]["message"] == "联机码已失效或已被使用"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_challenge_api_已使用联机码返回具体原因(realtime_api_setup):
|
||||
contest, first_client, second_client = realtime_api_setup
|
||||
created = first_client.post(
|
||||
f"/api/v1/contests/{contest.slug}/challenges/",
|
||||
{},
|
||||
content_type="application/json",
|
||||
)
|
||||
second_client.post(
|
||||
"/api/v1/contests/challenges/join/",
|
||||
{"challenge_code": created.json()["challenge_code"]},
|
||||
content_type="application/json",
|
||||
)
|
||||
third = User.objects.create_user(
|
||||
username="api_player_three",
|
||||
password="StrongPass_2026",
|
||||
nickname="API 玩家三",
|
||||
)
|
||||
third_client = Client()
|
||||
third_client.force_login(third)
|
||||
|
||||
response = third_client.post(
|
||||
"/api/v1/contests/challenges/join/",
|
||||
{"challenge_code": created.json()["challenge_code"]},
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json()["error"]["message"] == "联机码已失效或已被使用"
|
||||
|
||||
Reference in New Issue
Block a user