fifa17-recon: reconcile authoritative tools with running backend (B)
- Add 8 files present in docker/fifa17-python/tools but missing from the top-level tree: fut_accounts.py + 7 test_*.py contracts (all committed in the server's docker tree; byte-identical to the running image). - Preserve newer responder work already matching the running container: utas_server.py (offlineSeason), lsx_responder_v2.py (OPENFUT_BIND), blaze_responder_v3b.py, autopatch.py, pow_server.py, fut_store.py, test_fut_contract.py, fifa17-hook-m1.sh. - Add 30 newer ghidra_queries (draft purchase/state, SBC 9-26, runtime registries). Local tree is now a strict superset of B with all shared files byte-identical.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Isolated account-scoped regression for the FUT match HTTP lifecycle.
|
||||
|
||||
Drives CREATE -> READY -> PLAY -> END through match_route using a temporary
|
||||
profile root. No live profile or server is touched.
|
||||
"""
|
||||
import importlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
TOOLS = os.path.dirname(os.path.abspath(__file__))
|
||||
if TOOLS not in sys.path:
|
||||
sys.path.insert(0, TOOLS)
|
||||
|
||||
|
||||
class Request:
|
||||
def __init__(self, path, body, command="POST"):
|
||||
self.path = path
|
||||
self.command = command
|
||||
self._body = json.dumps(body).encode("utf-8")
|
||||
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory() as state:
|
||||
os.environ["FUT_ACCOUNT_PATH"] = os.path.join(state, "active_account.json")
|
||||
os.environ["FUT_PROFILE_ROOT"] = os.path.join(state, "accounts")
|
||||
os.environ.pop("FUT_PROFILE", None)
|
||||
|
||||
import fut_account
|
||||
import fut_store
|
||||
import fut_accounts
|
||||
import utas_server
|
||||
importlib.reload(fut_account)
|
||||
importlib.reload(fut_store)
|
||||
importlib.reload(fut_accounts)
|
||||
importlib.reload(utas_server)
|
||||
|
||||
persona_id = 909001
|
||||
fut_accounts.activate({"personaId": persona_id, "personaName": "MATCH_TEST"})
|
||||
initial = fut_store.STORE.load()
|
||||
initial_coins = initial["coins"]
|
||||
initial_next_id = initial["nextItemId"]
|
||||
|
||||
status, created = utas_server.match_route(
|
||||
Request("/ut/game/fifa17/match", {}))
|
||||
assert status == 200
|
||||
match_id = created["id"]
|
||||
assert created["reportIdEnabled"] is False
|
||||
assert fut_store.STORE.load()["nextItemId"] == initial_next_id + 1
|
||||
|
||||
status, ready = utas_server.match_route(
|
||||
Request("/ut/game/fifa17/match/ready", {"matchId": match_id}))
|
||||
assert status == 200
|
||||
assert ready == {"matchId": match_id, "opponentPersonaId": 0}
|
||||
|
||||
next_id_before_play = fut_store.STORE.load()["nextItemId"]
|
||||
status, played = utas_server.match_route(
|
||||
Request("/ut/game/fifa17/match", {"matchId": match_id}))
|
||||
assert status == 200
|
||||
assert played == {}
|
||||
assert fut_store.STORE.load()["nextItemId"] == next_id_before_play
|
||||
|
||||
status, ended = utas_server.match_route(Request(
|
||||
"/ut/game/fifa17/match/end",
|
||||
{"matchId": match_id, "endReason": "WIN",
|
||||
"myMatchStats": {"goals": 2},
|
||||
"opponentMatchStats": {"goals": 1}},
|
||||
))
|
||||
assert status == 200
|
||||
expected_reward = (utas_server.MATCH_COINS["won"]
|
||||
+ utas_server.MATCH_PARTICIPATION)
|
||||
assert ended["allCoins"] == initial_coins + expected_reward
|
||||
|
||||
profile_path = os.path.join(state, "accounts", str(persona_id),
|
||||
"fifa17_profile.json")
|
||||
persisted = json.load(open(profile_path, encoding="utf-8"))
|
||||
assert persisted["coins"] == initial_coins + expected_reward
|
||||
assert persisted["record"] == {"won": 1, "draw": 0, "loss": 0}
|
||||
assert persisted["matchesPlayed"] == 1
|
||||
|
||||
print("match lifecycle persistence: PASS")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user