"""Адресаты событий партии. Рейтинг общий (#80): завершённая партия двигает витрины всех игроков, поэтому игроки вне группы получают событие ratings (#88).""" from __future__ import annotations from fastapi.testclient import TestClient from tests.conftest import add_group_member, csrf_headers, finish_match, login, start_match def _capture_events(monkeypatch) -> list[tuple[list[int], dict]]: from app.core import events published: list[tuple[list[int], dict]] = [] monkeypatch.setattr( events.hub, "publish", lambda ids, event: published.append((list(ids), event)) ) return published def _recipients(published: list[tuple[list[int], dict]], kind: str) -> set[int]: return {uid for ids, e in published if e.get("type") == kind for uid in ids} def _two_groups(client: TestClient, engine) -> tuple[dict, int, int, int, list[int]]: """Хост и Игрок2 в группе партии, Чужой — только в другой группе хоста.""" me = login(client, "Хост") exps = [e["id"] for e in client.get("/api/expansions").json()] def group(name: str) -> int: return client.post( "/api/groups", json={"name": name, "expansion_ids": exps}, headers=csrf_headers(client) ).json()["id"] gid, other_gid = group("Группа"), group("Другая") p2 = add_group_member(engine, gid, "Игрок2") outsider = add_group_member(engine, other_gid, "Чужой") fids = [f["id"] for f in client.get(f"/api/groups/{gid}/factions").json()] return me, gid, p2, outsider, fids def test_finished_match_reaches_players_outside_group(client: TestClient, engine, monkeypatch): me, gid, p2, outsider, fids = _two_groups(client, engine) published = _capture_events(monkeypatch) started = start_match( client, gid, [{"user_id": me["id"], "faction_id": fids[0]}, {"user_id": p2, "faction_id": fids[1]}], ) assert started.status_code == 200, started.text # Незавершённая партия рейтинг не двигает — знать о ней нужно только группе. assert _recipients(published, "match") == {me["id"], p2} assert _recipients(published, "ratings") == set() published.clear() fin = finish_match( client, started.json()["id"], [{"user_id": me["id"], "place": 1}, {"user_id": p2, "place": 2}] ) assert fin.status_code == 200, fin.text assert _recipients(published, "match") == {me["id"], p2} ratings = _recipients(published, "ratings") assert outsider in ratings assert not ratings & {me["id"], p2} # группа уже получила подробное событие def test_deleting_finished_match_reaches_players_outside_group( client: TestClient, engine, monkeypatch ): """Удаление завершённой партии пересчитывает рейтинг всех, кто играл после неё.""" me, gid, p2, outsider, fids = _two_groups(client, engine) mid = start_match( client, gid, [{"user_id": me["id"], "faction_id": fids[0]}, {"user_id": p2, "faction_id": fids[1]}], ).json()["id"] finish_match(client, mid, [{"user_id": me["id"], "place": 1}, {"user_id": p2, "place": 2}]) published = _capture_events(monkeypatch) version = client.get(f"/api/matches/{mid}").json()["version"] r = client.delete( f"/api/matches/{mid}", params={"expected_version": version}, headers=csrf_headers(client) ) assert r.status_code == 200, r.text assert _recipients(published, "match") == {me["id"], p2} assert outsider in _recipients(published, "ratings")