Spaces:
Sleeping
Sleeping
| import sys | |
| import os | |
| import json | |
| import math | |
| # Add the project root to sys.path | |
| sys.path.append(os.getcwd()) | |
| from rl_env.environment import ATCEnv | |
| from rl_env.models import ATCAction | |
| def test_telemetry(): | |
| print("--- Starting LLM-Native Telemetry Test ---") | |
| env = ATCEnv(airport_code="VOCB") | |
| # Reset returns JSON string | |
| print("\n[1] Verifying Reset (Initial Telemetry)...") | |
| telemetry_str = env.reset(task="single_approach") | |
| assert isinstance(telemetry_str, str), "Reset should return a raw JSON string" | |
| telemetry = json.loads(telemetry_str) | |
| assert "step_telemetry" in telemetry, "Telemetry missing key 'step_telemetry'" | |
| aircraft = telemetry["step_telemetry"]["aircraft_metrics"] | |
| assert len(aircraft) > 0, "No aircraft metrics found" | |
| ac = aircraft[0] | |
| print(f"Callsign: {ac['callsign']}") | |
| print(f"Initial Severity Index: {ac['severity_index']}") | |
| assert ac["severity_index"] == 1.0, "Initial severity should be 1.0" | |
| # 2. Test Command Rejection | |
| print("\n[2] Testing Command Rejection Tracking...") | |
| # Try to TAXI while ENROUTE | |
| action = ATCAction(commands=[f"ATC TAXI {ac['callsign']} RWY_1"]) | |
| response_str = env.step(action) | |
| assert isinstance(response_str, str), "Step should return a raw JSON string" | |
| telemetry = json.loads(response_str) | |
| ac_telemetry = next(a for a in telemetry["step_telemetry"]["aircraft_metrics"] if a["callsign"] == ac["callsign"]) | |
| print(f"Rejections: {ac_telemetry['command_rejections']}") | |
| assert len(ac_telemetry["command_rejections"]) > 0, "Rejection not logged" | |
| assert "Must be ON_GATE" in ac_telemetry["command_rejections"][0] | |
| # 3. Test Time & State Tracking | |
| print("\n[3] Testing Time & State Tracking...") | |
| # Advance 10 steps | |
| for _ in range(9): | |
| env.step(ATCAction(commands=[])) | |
| response_str = env.step(ATCAction(commands=[])) | |
| telemetry = json.loads(response_str) | |
| ac_telemetry = next(a for a in telemetry["step_telemetry"]["aircraft_metrics"] if a["callsign"] == ac["callsign"]) | |
| print(f"Total Time Active: {ac_telemetry['timing_stats']['total_time_active_sec']}") | |
| assert ac_telemetry["timing_stats"]["total_time_active_sec"] >= 11, "Time tracking failed" | |
| # 4. Test Safety Metrics | |
| print("\n[4] Testing Safety Metrics...") | |
| ac_obj = env.engine.aircrafts[ac["callsign"]] | |
| env.engine.add_aircraft( | |
| callsign="BOT_CONFLICT", | |
| ac_type="B737", | |
| weight_class="Medium", | |
| gate="N", | |
| altitude=ac_obj.altitude, | |
| heading=ac_obj.heading, | |
| speed=ac_obj.speed | |
| ) | |
| conflict_ac = env.engine.aircrafts["BOT_CONFLICT"] | |
| conflict_ac.x, conflict_ac.y = ac_obj.x + 1.0, ac_obj.y + 1.0 | |
| response_str = env.step(ATCAction(commands=[])) | |
| telemetry = json.loads(response_str) | |
| ac_telemetry = next(a for a in telemetry["step_telemetry"]["aircraft_metrics"] if a["callsign"] == ac["callsign"]) | |
| print(f"Separation Warnings: {ac_telemetry['safety_metrics']['separation_warnings_triggered']}") | |
| assert ac_telemetry["safety_metrics"]["separation_warnings_triggered"] > 0, "Separation warning not tracked" | |
| # 5. Test Severity Index (Base-2 capped formula) | |
| print("\n[5] Testing Severity Index Scaling...") | |
| ac_obj.fuel_level = 5.0 # Trigger emergency | |
| env.step(ATCAction(commands=[])) | |
| # Advance 40 seconds | |
| for _ in range(39): | |
| env.step(ATCAction(commands=[])) | |
| response_str = env.step(ATCAction(commands=[])) | |
| telemetry = json.loads(response_str) | |
| ac_telemetry = next(a for a in telemetry["step_telemetry"]["aircraft_metrics"] if a["callsign"] == ac["callsign"]) | |
| # 40 seconds = 4 sets of 10s. Base-2 should be roughly 2^4 = 16 | |
| print(f"Emergency Timer: {ac_obj.emergency_timer}") | |
| print(f"Severity Index: {ac_telemetry['severity_index']}") | |
| # 2^(40/10) = 2^4 = 16.0 | |
| assert 15.0 < ac_telemetry["severity_index"] < 17.0, f"Severity index scaling incorrect: {ac_telemetry['severity_index']}" | |
| # 6. Test Metric Flushing | |
| print("\n[6] Testing Metric Flushing...") | |
| del env.engine.aircrafts["BOT_CONFLICT"] | |
| response_str = env.step(ATCAction(commands=[])) | |
| telemetry = json.loads(response_str) | |
| ac_telemetry = next(a for a in telemetry["step_telemetry"]["aircraft_metrics"] if a["callsign"] == ac["callsign"]) | |
| assert len(ac_telemetry["command_rejections"]) == 0, "Rejections not flushed" | |
| assert ac_telemetry["safety_metrics"]["separation_warnings_triggered"] == 0, "Safety metrics not flushed" | |
| print("\n--- LLM-NATIVE TELEMETRY TEST PASSED ---") | |
| if __name__ == "__main__": | |
| try: | |
| test_telemetry() | |
| except Exception as e: | |
| print(f"\n[ERROR] Test failed: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| sys.exit(1) | |