feat(fifa17): own club/stats/{year,consumables} in Rust (Core-accurate)
Migrate the MY CLUB stat set from the Python proxy to a Rust handler computing Core-accurate counts: player tiers + rare from the collection, staff/consumable families from catalog kind+subtype, per-nation buckets via the reverse entity resolver. Faithful port of fut_club_stats.py (VOCAB + global_counts + context_rows). Unlike the oracle (stale profile + synthetic consumable shelf), this reflects the real imported content (incl. the content-gap consumables/staff). Fail-closed 503 on Core error. club/stats/country|league|team sub-screens remain Python (documented). Adds adapter club_stats module (5 tests), host handler + classify arm + resolver subtype_of/rareflag_of, ownership + integration tests; reachability tool splits club/stats global(migrated) vs context(residual).
This commit is contained in:
@@ -1434,3 +1434,40 @@ fn hub_counts_players_from_core_no_python() {
|
||||
);
|
||||
assert_eq!(rec.lock().len(), 0, "hub never reaches Python");
|
||||
}
|
||||
|
||||
/// `GET /club/stats/year` is served from Rust with Core-accurate player tier
|
||||
/// counts (contextId 1 global bucket), never reaching Python.
|
||||
#[test]
|
||||
fn club_stats_year_counts_tiers_from_core_no_python() {
|
||||
let items = vec![
|
||||
item("oc1", "card_a", 90, "ST", "Brazil", "La Liga", "Barcelona"), // gold
|
||||
item("oc2", "card_b", 70, "CM", "Spain", "La Liga", "Real Madrid"), // silver
|
||||
item("oc3", "card_c", 60, "CB", "France", "Ligue 1", "PSG"), // bronze
|
||||
];
|
||||
let core = Arc::new(FakeCore::new(items, 3));
|
||||
let (py_url, rec) = spawn_mock_python();
|
||||
let server = build_server(core, &py_url, None);
|
||||
|
||||
let resp = server.handle("GET", "/ut/game/fifa17/club/stats/year", &[], b"");
|
||||
assert_eq!(resp.status, 200);
|
||||
let body: Value = serde_json::from_slice(&resp.body).unwrap();
|
||||
let g: std::collections::HashMap<String, i64> = body["stat"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|r| r["contextId"] == 1)
|
||||
.map(|r| {
|
||||
(
|
||||
r["type"].as_str().unwrap().to_string(),
|
||||
r["typeValue"].as_i64().unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(g["players"], 3);
|
||||
assert_eq!(g["playersGold"], 1);
|
||||
assert_eq!(g["playersSilver"], 1);
|
||||
assert_eq!(g["playersBronze"], 1);
|
||||
assert_eq!(g["consumables"], 0);
|
||||
assert_eq!(g["staff"], 0);
|
||||
assert_eq!(rec.lock().len(), 0, "club/stats never reaches Python");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user