import pytest from asgiref.sync import async_to_sync from channels.layers import get_channel_layer from channels.routing import URLRouter from channels.testing import WebsocketCommunicator from django.urls import path from accounts.models import User from contest.consumers import MatchConsumer from contest.models import Contest, Question, RealtimeMatch @pytest.mark.django_db(transaction=True) def test_match_consumer_双方连接并同步答题进度(): first = User.objects.create_user( username="socket_player_one", password="StrongPass_2026", nickname="WS 玩家一", ) second = User.objects.create_user( username="socket_player_two", password="StrongPass_2026", nickname="WS 玩家二", ) outsider = User.objects.create_user( username="socket_outsider", password="StrongPass_2026", nickname="WS 局外人", ) contest = Contest.objects.create( slug="socket-contest", title="WebSocket 联机赛", kind=Contest.Kind.REALTIME, track=Question.Track.STANDARD, status=Contest.Status.PUBLISHED, ) match = RealtimeMatch.objects.create( contest=contest, player_one=first, player_two=second, player_one_rating=first.rating, player_two_rating=second.rating, status=RealtimeMatch.Status.ACTIVE, ) application = URLRouter( [ path( "ws/test//", MatchConsumer.as_asgi(), ) ] ) async def scenario(): outsider_socket = WebsocketCommunicator(application, f"/ws/test/{match.id}/") outsider_socket.scope["user"] = outsider outsider_connected, close_code = await outsider_socket.connect() assert not outsider_connected assert close_code == 4403 first_socket = WebsocketCommunicator(application, f"/ws/test/{match.id}/") second_socket = WebsocketCommunicator(application, f"/ws/test/{match.id}/") first_socket.scope["user"] = first second_socket.scope["user"] = second first_connected, _ = await first_socket.connect() second_connected, _ = await second_socket.connect() assert first_connected and second_connected assert (await first_socket.receive_json_from())["type"] == "connected" assert (await second_socket.receive_json_from())["type"] == "connected" await first_socket.send_json_to({"type": "progress", "answered_count": 3}) first_progress = await first_socket.receive_json_from() second_progress = await second_socket.receive_json_from() assert first_progress["answered_count"] == 3 assert second_progress["answered_count"] == 3 assert second_progress["user_id"] == str(first.id) await get_channel_layer().group_send( f"match_{match.id}", {"type": "match.state", "reason": "completed"}, ) assert (await first_socket.receive_json_from())["reason"] == "completed" assert (await second_socket.receive_json_from())["reason"] == "completed" await first_socket.disconnect() await second_socket.disconnect() async_to_sync(scenario)()