diff --git a/l4d2web/l4d2web/routes/server_routes.py b/l4d2web/l4d2web/routes/server_routes.py index 132f266..37876e7 100644 --- a/l4d2web/l4d2web/routes/server_routes.py +++ b/l4d2web/l4d2web/routes/server_routes.py @@ -260,9 +260,11 @@ def live_state_fragment(server_id: int) -> Response: ServerPlayerSession.name_at_join, ) .order_by(func.max(ServerPlayerSession.left_at).desc()) - .limit(20) ).all() + recent_total = len(recent_rows) + recent_overview = recent_rows[:10] + return render_template( "_live_state.html", server=server, @@ -270,5 +272,7 @@ def live_state_fragment(server_id: int) -> Response: snapshot_fresh=(latest is not None and latest.last_seen_at >= cutoff), current_players=current_rows, recent_players=recent_rows, + recent_players_overview=recent_overview, + recent_players_total_count=recent_total, poll_seconds=max(1, int(current_app.config.get("LIVE_STATE_POLL_SECONDS", 5))), ) diff --git a/l4d2web/tests/test_status_and_server_logs.py b/l4d2web/tests/test_status_and_server_logs.py index 177dbca..3201cbc 100644 --- a/l4d2web/tests/test_status_and_server_logs.py +++ b/l4d2web/tests/test_status_and_server_logs.py @@ -71,3 +71,39 @@ def test_status_precedence() -> None: from l4d2web.services.status import compute_display_state assert compute_display_state("start", "stopped") == "starting" + + +@pytest.mark.xfail(reason="template change in Task 3 will satisfy this", strict=True) +def test_live_state_exposes_recent_overview_and_total_count(owner_client_with_server) -> None: + """Route must expose recent_players_overview (≤10) and recent_players_total_count. + + The body-text assertions depend on the template change in Task 3. + The xfail marker will be removed once Task 3 lands. + """ + from datetime import timedelta + from l4d2web.models import ServerPlayerSession + + client, server_id = owner_client_with_server + + now = datetime.now(UTC) + total = 13 + + with session_scope() as db: + for i in range(total): + db.add(ServerPlayerSession( + server_id=server_id, + steam_id_64=str(76561190000000000 + i), + joined_at=now - timedelta(hours=i + 2), + left_at=now - timedelta(hours=i + 1), + name_at_join=f"Player{i}", + min_ping=10, + max_ping=50, + )) + + res = client.get(f"/servers/{server_id}/live-state") + assert res.status_code == 200 + html = res.get_data(as_text=True) + + # These assertions depend on the Task 3 template changes. + assert "13 Recent" in html + assert html.count("recent-chip") <= 10