Added real timetable support
This commit is contained in:
@@ -187,3 +187,88 @@ async def test_admin_client_connect_and_actions(monkeypatch):
|
||||
client._protocol = BadProtocol()
|
||||
await client.quit()
|
||||
assert client.shutdown_event.is_set()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_get_timetable_request_and_response():
|
||||
client = OpenTTDAdminClient("127.0.0.1", port=3977, admin_name="TestAdmin")
|
||||
proto = MockProtocol()
|
||||
client._protocol = proto
|
||||
client._transport = MockTransport()
|
||||
|
||||
task = asyncio.ensure_future(client.get_timetable(5))
|
||||
await asyncio.sleep(0) # let the task send the request
|
||||
|
||||
# First use auto-subscribes to Gamescript updates, then sends the query.
|
||||
assert len(proto.sent) == 2
|
||||
assert proto.sent[0][2] == PacketAdminType.AdminUpdateFrequency
|
||||
assert decode_gamescript_payload(proto.sent[1]) == {
|
||||
"command": "get_timetable", "vehicle_id": 5, "request_id": 1,
|
||||
}
|
||||
|
||||
response = {"command": "get_timetable", "vehicle_id": 5, "request_id": 1,
|
||||
"lateness": 0, "start_tick": 0, "current_order_time": 3,
|
||||
"total_duration": -1, "orders": []}
|
||||
await client.receive_ServerGamescript(None, data=response)
|
||||
assert await task == response
|
||||
assert client._gs_futures == {}
|
||||
|
||||
# Second call must not re-subscribe and must use a fresh request id.
|
||||
task = asyncio.ensure_future(client.get_timetable(9))
|
||||
await asyncio.sleep(0)
|
||||
assert len(proto.sent) == 3
|
||||
assert decode_gamescript_payload(proto.sent[2])["request_id"] == 2
|
||||
await client.receive_ServerGamescript(None, data={"request_id": 2, "orders": []})
|
||||
assert (await task)["orders"] == []
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_get_timetable_timeout():
|
||||
client = OpenTTDAdminClient("127.0.0.1", port=3977, admin_name="TestAdmin")
|
||||
client._protocol = MockProtocol()
|
||||
client._transport = MockTransport()
|
||||
|
||||
with pytest.raises(asyncio.TimeoutError):
|
||||
await client.get_timetable(5, timeout=0.05)
|
||||
assert client._gs_futures == {}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_get_timetable_error_response():
|
||||
client = OpenTTDAdminClient("127.0.0.1", port=3977, admin_name="TestAdmin")
|
||||
client._protocol = MockProtocol()
|
||||
client._transport = MockTransport()
|
||||
|
||||
task = asyncio.ensure_future(client.get_timetable(65535))
|
||||
await asyncio.sleep(0)
|
||||
await client.receive_ServerGamescript(
|
||||
None, data={"command": "get_timetable", "vehicle_id": 65535,
|
||||
"request_id": 1, "error": "invalid_vehicle"})
|
||||
with pytest.raises(ValueError, match="invalid_vehicle"):
|
||||
await task
|
||||
assert client._gs_futures == {}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_get_timetable_disconnect_fails_pending():
|
||||
client = OpenTTDAdminClient("127.0.0.1", port=3977, admin_name="TestAdmin")
|
||||
client._protocol = MockProtocol()
|
||||
client._transport = MockTransport()
|
||||
|
||||
task = asyncio.ensure_future(client.get_timetable(5))
|
||||
await asyncio.sleep(0)
|
||||
client.disconnect(None)
|
||||
with pytest.raises(ConnectionError):
|
||||
await task
|
||||
assert client._gs_futures == {}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_gamescript_passthrough_unmatched():
|
||||
client = OpenTTDAdminClient("127.0.0.1", port=3977, admin_name="TestAdmin")
|
||||
client._protocol = MockProtocol()
|
||||
client._transport = MockTransport()
|
||||
|
||||
gs_events = []
|
||||
client.on_gamescript = lambda data: gs_events.append(data)
|
||||
|
||||
# No request_id, unknown request_id, and non-dict payloads all pass through.
|
||||
await client.receive_ServerGamescript(None, data={"vehicles": []})
|
||||
await client.receive_ServerGamescript(None, data={"request_id": 999, "orders": []})
|
||||
await client.receive_ServerGamescript(None, data="plain string")
|
||||
assert gs_events == [{"vehicles": []}, {"request_id": 999, "orders": []}, "plain string"]
|
||||
|
||||
@@ -429,6 +429,41 @@ async def test_e2e_admin_list_vehicles_specific_company(connected_admin):
|
||||
assert "vehicles" in responses[-1]
|
||||
assert isinstance(responses[-1]["vehicles"], list)
|
||||
|
||||
@pytest.mark.e2e
|
||||
@pytest.mark.asyncio
|
||||
async def test_e2e_admin_get_timetable_valid_vehicle(connected_admin):
|
||||
# Public function: get_timetable()
|
||||
# Input 1: a real vehicle id discovered via list_vehicles
|
||||
responses = []
|
||||
connected_admin.on_gamescript = lambda data: responses.append(data)
|
||||
await connected_admin.update_frequency(AdminUpdateType.Gamescript, AdminUpdateFrequency.Automatic)
|
||||
await connected_admin.list_vehicles()
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
assert len(responses) >= 1 and "vehicles" in responses[-1]
|
||||
vehicles = responses[-1]["vehicles"]
|
||||
if not vehicles:
|
||||
pytest.skip("No vehicles on the test server to query a timetable for.")
|
||||
vid = vehicles[0]["id"]
|
||||
|
||||
data = await connected_admin.get_timetable(vid, timeout=10.0)
|
||||
assert data["vehicle_id"] == vid
|
||||
for key in ("lateness", "start_tick", "current_order_time", "total_duration", "orders"):
|
||||
assert key in data
|
||||
assert isinstance(data["orders"], list)
|
||||
for order in data["orders"]:
|
||||
for key in ("position", "wait_time", "travel_time", "wait_timetabled",
|
||||
"travel_timetabled", "wait_fixed", "travel_fixed", "leave_type", "max_speed"):
|
||||
assert key in order
|
||||
|
||||
@pytest.mark.e2e
|
||||
@pytest.mark.asyncio
|
||||
async def test_e2e_admin_get_timetable_invalid_vehicle(connected_admin):
|
||||
# Public function: get_timetable()
|
||||
# Input 2: an id no vehicle can have -> GameScript reports invalid_vehicle
|
||||
with pytest.raises(ValueError, match="invalid_vehicle"):
|
||||
await connected_admin.get_timetable(65535, timeout=10.0)
|
||||
|
||||
|
||||
# --- Protocol Public Functions ---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user