Merge branch 'main' into claude/silly-lederberg-231f6c
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s

Conflicted only on the README feature list, where main's list_cargo()
bullet and this branch's bridge bullet were added at the same spot. Kept
both: list_cargo() with the other cargo queries, and the bridge one last,
since it is about what all of them run against.

list_cargo() landing also makes tests/test_gamescript.py's command check
meaningful in the other direction -- the bridge has answered list_cargo
all along with nothing sending it, which is exactly the asymmetry that
check tolerates on purpose.

Co-Authored-By: Claude <[email protected]>
This commit is contained in:
2026-08-31 19:12:41 +02:00
co-authored by Claude
7 changed files with 117 additions and 4 deletions
+38
View File
@@ -755,6 +755,44 @@ async def test_e2e_admin_get_station_cargo_invalid_cargo(connected_admin):
with pytest.raises(ValueError, match="invalid_cargo"):
await connected_admin.get_station_cargo(stations[0]["id"], 250, timeout=10.0)
@pytest.mark.e2e
@pytest.mark.asyncio
async def test_e2e_admin_list_cargo_table(connected_admin):
# Public function: list_cargo()
# Input 1: an explicit timeout. Every game has a cargo table, so an empty list would be a bug.
data = await connected_admin.list_cargo(timeout=10.0)
assert isinstance(data["cargo"], list) and data["cargo"]
for cargo in data["cargo"]:
for key in ("cargo_id", "label", "freight"):
assert key in cargo
assert cargo["freight"] in (0, 1)
ids = [cargo["cargo_id"] for cargo in data["cargo"]]
assert len(ids) == len(set(ids))
# Any cargo set carries passengers as well as freight, so both kinds must show up.
assert any(cargo["freight"] == 0 for cargo in data["cargo"])
assert any(cargo["freight"] == 1 for cargo in data["cargo"])
@pytest.mark.e2e
@pytest.mark.asyncio
async def test_e2e_admin_list_cargo_resolves_station_cargo_ids(connected_admin):
# Public function: list_cargo()
# Input 2: the default timeout. The point of the call: naming the bare ids get_station() returns.
responses = []
connected_admin.on_gamescript = lambda data: responses.append(data)
await connected_admin.update_frequency(AdminUpdateType.Gamescript, AdminUpdateFrequency.Automatic)
await connected_admin.list_stations()
await asyncio.sleep(0.5)
assert responses and "stations" in responses[-1]
stations = responses[-1]["stations"]
if not stations:
pytest.skip("No stations on the test server to query.")
labels = {cargo["cargo_id"]: cargo["label"] for cargo in (await connected_admin.list_cargo())["cargo"]}
detail = await connected_admin.get_station(stations[0]["id"], timeout=10.0)
for cargo in detail["cargo"]:
assert cargo["cargo_id"] in labels
# --- Game Events ---