233 lines
10 KiB
Python
233 lines
10 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from app.payloads import build_stats_player_profile_payload
|
|
from app.rcon_historical_player_stats import (
|
|
_build_profile_active_time_payload,
|
|
get_rcon_materialized_player_stats,
|
|
)
|
|
|
|
|
|
class StatsPlayerProfilePayloadTests(unittest.TestCase):
|
|
def test_player_stats_read_model_keeps_payload_valid_when_active_time_lookup_fails(self) -> None:
|
|
selected_row = {
|
|
"period_type": "weekly",
|
|
"window_kind": "current-week",
|
|
"period_start": "2026-06-01T00:00:00Z",
|
|
"period_end": "2026-06-08T00:00:00Z",
|
|
"server_id": "all-servers",
|
|
"player_id": "76561198000000000",
|
|
"player_name": "Steam Player",
|
|
"matches_considered": 4,
|
|
"kills": 20,
|
|
"deaths": 10,
|
|
"teamkills": 0,
|
|
"ranking_position": 4,
|
|
"updated_at": "2026-06-11T12:00:00Z",
|
|
"first_seen_at": "2026-06-01T01:00:00Z",
|
|
"last_seen_at": "2026-06-08T01:00:00Z",
|
|
}
|
|
with (
|
|
patch(
|
|
"app.rcon_historical_player_stats._get_player_period_stats_read_model",
|
|
return_value=(
|
|
{
|
|
"player_id": "76561198000000000",
|
|
"player_name": "Steam Player",
|
|
"server_id": "all-servers",
|
|
"timeframe": "weekly",
|
|
"window_start": None,
|
|
"window_end": None,
|
|
"window_kind": "current-week",
|
|
"matches_considered": 4,
|
|
"kills": 20,
|
|
"deaths": 10,
|
|
"teamkills": 0,
|
|
"player_active_seconds": None,
|
|
"player_active_minutes": None,
|
|
"kpm": None,
|
|
"kpm_status": "missing_active_time",
|
|
"active_time_source": "unavailable",
|
|
"active_time_coverage": {
|
|
"eligible_matches": 0,
|
|
"real_source_matches": 0,
|
|
"observed_matches": 0,
|
|
"total_matches_considered": 4,
|
|
"eligible_kills": 0,
|
|
"minimum_active_seconds": 60,
|
|
"sources": [],
|
|
},
|
|
"platform": "steam",
|
|
"steam_id_64": "76561198000000000",
|
|
"external_profile_links": {
|
|
"steam": "https://steamcommunity.com/profiles/76561198000000000",
|
|
"hellor": "https://hellor.pro/player/76561198000000000",
|
|
"hll_records": "https://hllrecords.com/profiles/76561198000000000",
|
|
"helo": "https://helo-system.de/statistics/players/76561198000000000?series=2024",
|
|
},
|
|
"weekly_ranking": {"metric": "kills", "ranking_position": 4},
|
|
"monthly_ranking": {"metric": "kills", "ranking_position": 7},
|
|
"source": {"primary_source": "rcon", "read_model": "player-period-stats"},
|
|
},
|
|
None,
|
|
),
|
|
),
|
|
):
|
|
payload = build_stats_player_profile_payload(
|
|
player_id="76561198000000000",
|
|
timeframe="weekly",
|
|
)
|
|
|
|
data = payload["data"]
|
|
self.assertEqual(data["matches_considered"], 4)
|
|
self.assertIsNone(data["kpm"])
|
|
self.assertEqual(data["kpm_status"], "missing_active_time")
|
|
self.assertIn("steam", data["external_profile_links"])
|
|
|
|
def test_player_stats_returns_lightweight_missing_payload_when_period_read_model_is_empty(self) -> None:
|
|
with patch(
|
|
"app.rcon_historical_player_stats._get_player_period_stats_read_model",
|
|
return_value=(None, "player-period-stats-empty"),
|
|
):
|
|
result = get_rcon_materialized_player_stats(
|
|
player_id="76561198000000000",
|
|
timeframe="weekly",
|
|
)
|
|
|
|
self.assertEqual(result["matches_considered"], 0)
|
|
self.assertEqual(result["kpm_status"], "missing_active_time")
|
|
self.assertEqual(result["platform"], "steam")
|
|
self.assertIn("steam", result["external_profile_links"])
|
|
self.assertEqual(result["source"]["missing_reason"], "player-period-stats-empty")
|
|
self.assertFalse(result["source"]["fallback_used"])
|
|
|
|
def test_build_stats_player_profile_payload_exposes_ready_real_kpm_and_external_links(self) -> None:
|
|
with patch(
|
|
"app.payloads.get_rcon_materialized_player_stats",
|
|
return_value={
|
|
"player_id": "76561198000000000",
|
|
"player_name": "Steam Player",
|
|
"server_id": "all-servers",
|
|
"timeframe": "weekly",
|
|
"window_start": None,
|
|
"window_end": None,
|
|
"window_kind": "current-week",
|
|
"matches_considered": 4,
|
|
"kills": 20,
|
|
"deaths": 10,
|
|
"teamkills": 0,
|
|
"player_active_seconds": 1200,
|
|
"player_active_minutes": 20.0,
|
|
"kpm": 1.0,
|
|
"kpm_status": "ready",
|
|
"active_time_source": "connection_intervals",
|
|
"active_time_coverage": {
|
|
"eligible_matches": 4,
|
|
"real_source_matches": 4,
|
|
"observed_matches": 4,
|
|
"total_matches_considered": 4,
|
|
"eligible_kills": 20,
|
|
"minimum_active_seconds": 60,
|
|
"sources": ["connection_intervals"],
|
|
},
|
|
"platform": "steam",
|
|
"steam_id_64": "76561198000000000",
|
|
"external_profile_links": {
|
|
"steam": "https://steamcommunity.com/profiles/76561198000000000",
|
|
"hellor": "https://hellor.pro/player/76561198000000000",
|
|
"hll_records": "https://hllrecords.com/profiles/76561198000000000",
|
|
"helo": "https://helo-system.de/statistics/players/76561198000000000?series=2024",
|
|
},
|
|
"weekly_ranking": {"metric": "kills", "ranking_position": 4},
|
|
"monthly_ranking": {"metric": "kills", "ranking_position": 7},
|
|
"source": {"primary_source": "rcon"},
|
|
},
|
|
):
|
|
payload = build_stats_player_profile_payload(
|
|
player_id="76561198000000000",
|
|
timeframe="weekly",
|
|
)
|
|
|
|
data = payload["data"]
|
|
self.assertEqual(data["kpm"], 1.0)
|
|
self.assertEqual(data["kpm_status"], "ready")
|
|
self.assertEqual(data["active_time_source"], "connection_intervals")
|
|
self.assertEqual(data["steam_id_64"], "76561198000000000")
|
|
self.assertEqual(data["platform"], "steam")
|
|
self.assertIn("steam", data["external_profile_links"])
|
|
|
|
def test_build_stats_player_profile_payload_keeps_kpm_null_when_connection_intervals_are_missing(self) -> None:
|
|
with patch(
|
|
"app.payloads.get_rcon_materialized_player_stats",
|
|
return_value={
|
|
"player_id": "epic-player-id",
|
|
"player_name": "Epic Player",
|
|
"server_id": "all-servers",
|
|
"timeframe": "monthly",
|
|
"window_start": None,
|
|
"window_end": None,
|
|
"window_kind": "current-month",
|
|
"matches_considered": 2,
|
|
"kills": 7,
|
|
"deaths": 4,
|
|
"teamkills": 0,
|
|
"player_active_seconds": None,
|
|
"player_active_minutes": None,
|
|
"kpm": None,
|
|
"kpm_status": "missing_connection_intervals",
|
|
"active_time_source": "event_span_fallback",
|
|
"active_time_coverage": {
|
|
"eligible_matches": 0,
|
|
"real_source_matches": 0,
|
|
"observed_matches": 2,
|
|
"total_matches_considered": 2,
|
|
"eligible_kills": 0,
|
|
"minimum_active_seconds": 60,
|
|
"sources": ["event_span_fallback"],
|
|
},
|
|
"platform": "epic",
|
|
"epic_id": "0123456789abcdef0123456789abcdef",
|
|
"external_profile_links": {
|
|
"hellor": "https://hellor.pro/player/0123456789abcdef0123456789abcdef",
|
|
"hll_records": "https://hllrecords.com/profiles/0123456789abcdef0123456789abcdef",
|
|
},
|
|
"weekly_ranking": {"metric": "kills", "ranking_position": None},
|
|
"monthly_ranking": {"metric": "kills", "ranking_position": None},
|
|
"source": {"primary_source": "rcon"},
|
|
},
|
|
):
|
|
payload = build_stats_player_profile_payload(
|
|
player_id="0123456789abcdef0123456789abcdef",
|
|
timeframe="monthly",
|
|
)
|
|
|
|
data = payload["data"]
|
|
self.assertIsNone(data["kpm"])
|
|
self.assertEqual(data["kpm_status"], "missing_connection_intervals")
|
|
self.assertNotIn("steam", data["external_profile_links"])
|
|
|
|
def test_profile_active_time_payload_marks_ready_only_for_real_connection_intervals(self) -> None:
|
|
payload = _build_profile_active_time_payload(
|
|
row={
|
|
"observed_matches": 3,
|
|
"real_source_matches": 3,
|
|
"eligible_matches": 3,
|
|
"player_active_seconds": 600,
|
|
"eligible_kills": 10,
|
|
"eligible_sources": "connection_intervals,connection_intervals_carryover",
|
|
"observed_sources": "connection_intervals,connection_intervals_carryover",
|
|
},
|
|
total_matches_considered=3,
|
|
min_active_seconds=60,
|
|
)
|
|
|
|
self.assertEqual(payload["kpm"], 1.0)
|
|
self.assertEqual(payload["kpm_status"], "ready")
|
|
self.assertEqual(payload["active_time_source"], "connection_intervals_mixed")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|