fifa17-python: commit working FUT backend deployment (client/server split)
Freeze the running offline FUT backend into version control as fifa17-recon/docker/fifa17-python/ - declarative and rebuildable from a fresh checkout: * OPENFUT_BIND / OPENFUT_ADVERTISE client/server split in the responders (lsx, blaze, roster, utas, pow) + entrypoint.sh; OPENFUT_ADVERTISE is required for remote mode (compose and entrypoint fail without it) * docker-compose.yml reproducing the frozen baseline container exactly (env, ports incl. the 8085->8080 POW-content remap, /state bind, restart) * .env.example / .env for site config - the LAN IP is never hardcoded in source * tools/ + data/ staged from openfut-fut-backend:python-baseline-2026-08-10, verified byte-identical to the running container at freeze time * client_arm.sh (the 105 client-side arming counterpart) * Dockerfile bakes /app/SHA256SUMS.txt so any image is self-identifying * docs/BASELINE-python-2026-08-10.md: frozen image/container/hash record, restore instructions and rebuild-equivalence procedure Secrets (redir key/cert, .env) and runtime state (docker/state) stay gitignored. The live container is untouched pending the .105 launcher audit.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regression tests for launcher-selected persistent FIFA 17 accounts."""
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
a = fut_accounts.activate({
|
||||
"personaId": 111001, "personaName": "TEST_A",
|
||||
"level": 12, "experience": 345, "experienceMax": 1000,
|
||||
"accountFunds": 50, "accountFundsCap": 100000,
|
||||
})
|
||||
assert a["personaId"] == 111001
|
||||
assert a["level"] == 12
|
||||
assert fut_store.STORE.coins() == 15000
|
||||
assert fut_store.STORE.unopened_packs() == [70]
|
||||
fut_store.STORE.spend(400)
|
||||
fut_store.STORE.consume_unopened_pack(70)
|
||||
|
||||
b = fut_accounts.activate({"personaId": 222002, "personaName": "TEST_B"})
|
||||
assert b["personaId"] == 222002
|
||||
assert fut_store.STORE.coins() == 15000
|
||||
assert fut_store.STORE.unopened_packs() == [70]
|
||||
|
||||
a2 = fut_accounts.activate({"personaId": 111001, "personaName": "TEST_A"})
|
||||
assert a2["personaId"] == 111001
|
||||
assert fut_store.STORE.coins() == 14600
|
||||
assert fut_store.STORE.unopened_packs() == []
|
||||
assert a2["level"] == 12
|
||||
assert a2["accountFunds"] == 50
|
||||
|
||||
active = json.load(open(os.environ["FUT_ACCOUNT_PATH"]))
|
||||
assert active["persona_id"] == 111001
|
||||
assert active["persona_name"] == "TEST_A"
|
||||
|
||||
# A second process-like Account instance must observe an atomic active
|
||||
# account file replacement rather than retaining its first loaded value.
|
||||
observer = fut_account.Account(os.environ["FUT_ACCOUNT_PATH"])
|
||||
assert observer.persona_id == 111001
|
||||
fut_accounts.activate({"personaId": 222002, "personaName": "TEST_B"})
|
||||
assert observer.persona_id == 222002
|
||||
|
||||
class Purchase:
|
||||
command = "POST"
|
||||
_body = b'{"packId":6,"useCredits":1,"usePreOrder":0,"currency":"COINS"}'
|
||||
|
||||
utas_server._OPENED_PACK_GRACE.clear()
|
||||
status, _ = utas_server.purchased_items(Purchase())
|
||||
assert status == 200
|
||||
assert utas_server._OPENED_PACK_GRACE == [6]
|
||||
status, catalog = utas_server.store_catalog(None)
|
||||
assert status == 200
|
||||
grace = [p for p in catalog["purchase"]
|
||||
if p.get("id") == 6 and p.get("unopened")]
|
||||
assert len(grace) == 1
|
||||
assert grace[0]["state"] == "active"
|
||||
assert grace[0]["displayGroup"]["value"] == "mypacks"
|
||||
|
||||
print("account profile isolation: PASS")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user