def test_wrong_id(): """ Expect a row in a dataframe with NAN if requested aircraft not in simulation. """ cmd = reset_simulation() assert cmd == True pos = aircraft_position(aircraft_id) # print(pos) assert pos.loc[aircraft_id].isnull().all() cmd = create_aircraft( aircraft_id=aircraft_id, type=type, latitude=latitude, longitude=longitude, heading=heading, flight_level=flight_level, speed=speed, ) assert cmd == True pos = aircraft_position([aircraft_id, aircraft_id_2]) assert len(pos.index) == 2 assert pos.loc[aircraft_id_2].isnull().all()
def test_route_waypoints(upload_test_sector_scenario): """ Test list_route(), direct_to_waypoint() """ cmd = reset_simulation() assert cmd == True upload_test_sector_scenario() # Get the position position = all_positions() acid1, acid2 = position.index route1 = list_route(acid1) route2 = list_route(acid2) assert route1["aircraft_id"] == acid1 assert route2["aircraft_id"] == acid2 assert route1["next_waypoint"] == 'FIYRE' assert route1["route_name"] == 'ASCENSION' assert len(route1["route_waypoints"]) == 5 assert route2["next_waypoint"] == 'SPIRT' assert route2["route_name"] == 'FALLEN' assert len(route2["route_waypoints"]) == 5 route2["route_waypoints"].reverse() assert all([ wp1 == wp2 for wp1, wp2 in zip(route1["route_waypoints"], route2["route_waypoints"]) ])
def test_change_heading(upload_test_sector_scenario): cmd = reset_simulation() assert cmd == True upload_test_sector_scenario() # Get the position position = all_positions() acid1, acid2 = position.index # Test with an invalid heading. invalid_heading = 400 with pytest.raises(AssertionError): change_heading(aircraft_id=acid1, heading=invalid_heading) # Give the command to change heading. # Aircraft is originally headed north (0 degrees) new_heading = 90 cmd = change_heading(aircraft_id=acid1, heading=new_heading) assert cmd == True # Check that the heading has changed. resp = simulation_step() assert resp == True new_position = all_positions() assert new_position.loc[acid1, "longitude"] > position.loc[acid1, "longitude"]
def test_no_positions(): """ Expect empty dataframe when no aircraft exist. """ cmd = reset_simulation() assert cmd == True pos_df = all_positions() assert pos_df.empty
def test_output_create_aircraft(): # reset so that no aircraft exist reset_simulation() output = create_aircraft(aircraft_id, type, latitude, longitude, heading, speed, altitude, flight_level) assert output == True with pytest.raises(HTTPError): create_aircraft( aircraft_id, type, latitude, longitude, heading, speed, altitude, flight_level, )
def test_aircraft_position(): cmd = reset_simulation() assert cmd == True cmd = create_aircraft( aircraft_id=aircraft_id, type=type, latitude=latitude, longitude=longitude, heading=heading, flight_level=flight_level, speed=speed, ) assert cmd == True cmd = create_aircraft( aircraft_id=aircraft_id_2, type=type_2, latitude=latitude_2, longitude=longitude_2, heading=heading_2, flight_level=flight_level_2, speed=speed_2, ) assert cmd == True pos = aircraft_position(aircraft_id) assert isinstance(pos, pd.DataFrame) assert len(pos.index) == 1 assert pos.loc[aircraft_id]["aircraft_type"] == type assert pos.loc[aircraft_id]["latitude"] == pytest.approx(0, abs=1e-5) assert pos.loc[aircraft_id]["longitude"] == pytest.approx(0, abs=1e-5) assert pos.loc[aircraft_id]["vertical_speed"] == 0 # flight level is returned in feet assert pos.loc[aircraft_id]["current_flight_level"] == flight_level * 100 assert pos.loc[aircraft_id]["ground_speed"] == 0 # check that dataframe has sim_t attribute assert isinstance(pos.sim_t, float) pos = aircraft_position([aircraft_id, aircraft_id_2]) assert len(pos.index) == 2 assert pos.loc[aircraft_id_2]["aircraft_type"] == type_2 assert pos.loc[aircraft_id_2]["latitude"] == pytest.approx(0, abs=1e-5) assert pos.loc[aircraft_id_2]["longitude"] == pytest.approx(0, abs=1e-5) assert pos.loc[aircraft_id_2]["vertical_speed"] == 0 # flight level is returned in feet assert pos.loc[aircraft_id_2]["current_flight_level"] == flight_level_2 * 100 assert pos.loc[aircraft_id_2]["ground_speed"] == 0
def test_upload_sector(rootdir): """ Create scenario on the simulator host and load. Check two aircraft created succesfully with associated route. """ test_sector = "dodo-test-sector" test_file = os.path.join(rootdir, test_sector) resp = reset_simulation() assert resp == True resp = upload_sector(filename="{}.geojson".format(test_file), sector_name=test_sector) assert resp == True
def test_async_request(upload_test_sector_scenario): """ Tests async_request() function """ cmd = reset_simulation() assert cmd == True upload_test_sector_scenario() # Get the position position = all_positions() acid1, acid2 = position.index commands = [] commands.append(async_change_altitude(aircraft_id=acid1, flight_level=100)) commands.append(async_change_heading(aircraft_id=acid1, heading=90)) results = batch(commands) assert results == True resp = simulation_step() assert resp == True new_position = all_positions() assert new_position.loc[acid1, "current_flight_level"] < position.loc[ acid1, "current_flight_level"] assert new_position.loc[acid1, "longitude"] > position.loc[acid1, "longitude"] # send more commands - return to original values more_commands = [] more_commands.append( async_change_altitude(aircraft_id=acid1, flight_level=400)) more_commands.append(async_change_speed(aircraft_id=acid1, speed=100)) results = batch(more_commands) assert results == True # send an invalid and a valid command commands_wrong = [] commands_wrong.append(async_change_heading(aircraft_id=acid1, heading=0)) commands_wrong.append(async_change_speed(aircraft_id=acid1, speed=-5)) with pytest.raises(Exception): results = batch(commands_wrong)
def test_wrong_id(): """ Test separation functions when one of provided IDs does not exist in simulation. """ cmd = reset_simulation() assert cmd == True separation0 = euclidean_separation(from_aircraft_id=aircraft_id) assert isinstance(separation0, pd.DataFrame) assert np.isnan(separation0.loc[aircraft_id, aircraft_id]) cmd = create_aircraft( aircraft_id=aircraft_id, type=type, latitude=latitude, longitude=longitude, heading=heading, flight_level=flight_level, speed=speed, ) assert cmd == True separation1 = geodesic_separation( from_aircraft_id=[aircraft_id, aircraft_id_2], to_aircraft_id=[aircraft_id, aircraft_id_2], ) assert isinstance(separation1, pd.DataFrame) assert np.isnan(separation1.loc[aircraft_id, aircraft_id_2]) separation2 = great_circle_separation( from_aircraft_id=[aircraft_id, aircraft_id_2], to_aircraft_id=aircraft_id) assert isinstance(separation2, pd.DataFrame) assert np.isnan(separation2.loc[aircraft_id_2, aircraft_id]) separation3 = vertical_separation( from_aircraft_id=aircraft_id, to_aircraft_id=[aircraft_id, aircraft_id_2]) assert isinstance(separation3, pd.DataFrame) assert np.isnan(separation3.loc[aircraft_id, aircraft_id_2]) separation4 = euclidean_separation(from_aircraft_id=aircraft_id, to_aircraft_id=aircraft_id_2) assert isinstance(separation4, pd.DataFrame) assert np.isnan(separation4.loc[aircraft_id, aircraft_id_2])
def test_flight_level(upload_test_sector_scenario): cmd = reset_simulation() assert cmd == True upload_test_sector_scenario() # Get the position position = all_positions() acid1, acid2 = position.index assert cleared_flight_level(acid1) == 400 assert requested_flight_level(acid1) == 400 # In BlueSky overflier aircraft is inialised below requested flight level assert 39995 < current_flight_level(acid1) <= 40000 assert cleared_flight_level(acid2) == 200 assert requested_flight_level(acid2) == 400 assert current_flight_level(acid2) == 20000
def test_loss_of_separation(): """ Tests loss_of_separation returns correct separation score. """ cmd = reset_simulation() assert cmd == True cmd = create_aircraft( aircraft_id=aircraft_id, type=type, latitude=latitude, longitude=longitude, heading=heading, flight_level=flight_level, speed=speed, ) assert cmd == True cmd = create_aircraft( aircraft_id=aircraft_id_2, type=type_2, latitude=latitude_2, longitude=longitude_2, heading=heading_2, flight_level=flight_level_2, speed=speed_2, ) assert cmd == True score1 = loss_of_separation(aircraft_id, aircraft_id_2) assert score1 == 0 score2 = loss_of_separation(aircraft_id, aircraft_id) assert score2 == -1 score3 = loss_of_separation(aircraft_id_2, aircraft_id_2) assert score3 == -1 new_aircraft_id = "TST3003" score4 = loss_of_separation(aircraft_id, new_aircraft_id) assert np.isnan(score4)
def test_change_speed(): cmd = reset_simulation() assert cmd == True aircraft_id = "TST1001" type = "B744" latitude = 0 longitude = 0 heading = 0 flight_level = 250 speed = 265 cmd = create_aircraft( aircraft_id=aircraft_id, type=type, latitude=latitude, longitude=longitude, heading=heading, flight_level=flight_level, speed=speed, ) assert cmd == True # Check the altitude. position = aircraft_position(aircraft_id) # In the returned data frame aircraft_id is uppercase. aircraft_id = aircraft_id.upper() # Aircaft initial speed differs from specified speed. assert position.loc[aircraft_id]["ground_speed"] > 200 # Test with an invalid speed. invalid_speed = -1 with pytest.raises(AssertionError): change_speed(aircraft_id=aircraft_id, speed=invalid_speed) # Give the command to change speed. new_speed = 400 cmd = change_speed(aircraft_id=aircraft_id, speed=new_speed) assert cmd == True
def test_change_altitude(upload_test_sector_scenario): cmd = reset_simulation() assert cmd == True upload_test_sector_scenario() # Get the position position = all_positions() acid1, acid2 = position.index # Give the command to descend. new_flight_level = 100 cmd = change_altitude(aircraft_id=acid1, flight_level=new_flight_level) assert cmd == True # Check that the new altitude is below the original one. resp = simulation_step() assert resp == True new_position = all_positions() assert new_position.loc[acid1, "current_flight_level"] < position.loc[ acid1, "current_flight_level"]
def test_upload_scenario(rootdir): """ Runs through a basic scenario covering all the main functionality (no aircraft commands are sent). """ resp = reset_simulation() assert resp == True # 1. SIMULATION SHOULD BE EMPTY info0 = simulation_info() assert info0["scenario_name"] is None assert len(info0["aircraft_ids"]) == 0 # 2. LOAD SECTOR AND SCENARIO test_scenario_file = os.path.join(rootdir, "dodo-test-scenario") test_sector_file = os.path.join(rootdir, "dodo-test-sector") resp = upload_sector(filename=f"{test_sector_file}.geojson", sector_name="test_sector") assert resp == True resp = upload_scenario(filename=f"{test_scenario_file}.json", scenario_name="test_scenario") assert resp == True # 3. CHECK SIMULATION HAS AIRCRAFT WITH POSITIONS AND ROUTES info = simulation_info() assert info["scenario_name"] == "test_scenario" assert len(info["aircraft_ids"]) == 2 pos = all_positions() assert isinstance(pos, pd.DataFrame) assert len(pos.index) == 2 acid1, acid2 = pos.index route1 = list_route(acid1) route2 = list_route(acid2) assert isinstance(route1, dict) assert isinstance(route2, dict) assert len(route1["route_waypoints"]) == 5 assert len(route2["route_waypoints"]) == 5 # 4. STEP FORWARD THE SIMULATION & CHECK IT ADVANCED (5 x 1 second scenario time) for i in range(5): info1 = simulation_info() resp = simulation_step() assert resp == True info2 = simulation_info() assert info2["scenario_time"] - info1["scenario_time"] == pytest.approx( 1.0) # EXPECT CHANGE IN AIRCRAFT LATITUDES # aircraft 1 is travelling from latitude ~51 to ~53 # aircraft 2 is heading in the opposite direction pos1 = all_positions() assert pos.loc[acid1, "longitude"] == pos1.loc[acid1, "longitude"] assert pos.loc[acid1, "latitude"] < pos1.loc[acid1, "latitude"] assert pos.loc[acid2, "longitude"] == pos1.loc[acid2, "longitude"] assert pos.loc[acid2, "latitude"] > pos1.loc[acid2, "latitude"] # 5. CHANGE STEP SIZE & TAKE STEP # SIMULATION SHOULD MOVE FOWARD BY MORE THAN BEFORE (10 second scenario time) resp = set_simulation_rate_multiplier(10) assert resp == True resp = simulation_step() assert resp == True info3 = simulation_info() assert info3["scenario_time"] - info2["scenario_time"] == pytest.approx( 10.0) # CHANGE IN AIRCRAFT LATITUDE SHOULD BE MORE IN THIS SINGLE 10s STEP # COMPARED TO PREVIOUS 5 x 1 second STEPS pos2 = all_positions() assert (abs(pos2.loc[acid1, "latitude"] - pos1.loc[acid1, "latitude"]) > abs(pos1.loc[acid1, "latitude"] - pos.loc[acid1, "latitude"])) assert (abs(pos2.loc[acid2, "latitude"] - pos1.loc[acid2, "latitude"]) > abs(pos1.loc[acid2, "latitude"] - pos.loc[acid2, "latitude"]))
def test_separation(expected_great_circle): """ Tests that all separation functions return a dataframe using a variety of inputs. """ cmd = reset_simulation() assert cmd == True cmd = create_aircraft( aircraft_id=aircraft_id, type=type, latitude=latitude, longitude=longitude, heading=heading, flight_level=flight_level, speed=speed, ) assert cmd == True cmd = create_aircraft( aircraft_id=aircraft_id_2, type=type_2, latitude=latitude_2, longitude=longitude_2, heading=heading_2, flight_level=flight_level_2, speed=speed_2, ) assert cmd == True separation1 = geodesic_separation( from_aircraft_id=[aircraft_id, aircraft_id_2], to_aircraft_id=[aircraft_id, aircraft_id_2], ) assert isinstance(separation1, pd.DataFrame) assert separation1.loc[aircraft_id, aircraft_id_2] == pytest.approx( 1000 * 176.92, 0.01) separation2 = great_circle_separation( from_aircraft_id=[aircraft_id, aircraft_id_2], to_aircraft_id=aircraft_id) assert isinstance(separation2, pd.DataFrame) expected = expected_great_circle(latitude, longitude, latitude_2, longitude_2) assert separation2.loc[aircraft_id_2, aircraft_id] == pytest.approx(expected, 0.01) separation3 = vertical_separation( from_aircraft_id=aircraft_id, to_aircraft_id=[aircraft_id, aircraft_id_2]) assert isinstance(separation3, pd.DataFrame) ## altitude is provided as flight_level, which must be converted to: # feet (*100) and then to metres (*0.3048) assert ( separation3.loc[aircraft_id, aircraft_id_2] == abs(flight_level - flight_level_2) * 100 * SCALE_FEET_TO_METRES) separation4 = euclidean_separation(from_aircraft_id=aircraft_id, to_aircraft_id=aircraft_id_2) assert isinstance(separation4, pd.DataFrame) ecef = pyproj.Proj(proj="geocent", ellps="WGS84", datum="WGS84") lla = pyproj.Proj(proj="latlong", ellps="WGS84", datum="WGS84") from_ECEF = pyproj.transform(lla, ecef, longitude, latitude, flight_level * 100 * SCALE_FEET_TO_METRES) to_ECEF = pyproj.transform(lla, ecef, longitude_2, latitude_2, flight_level_2 * 100 * SCALE_FEET_TO_METRES) assert separation4.loc[aircraft_id, aircraft_id_2] == pytest.approx( euclidean(from_ECEF, to_ECEF), 0.01) separation5 = euclidean_separation(from_aircraft_id=aircraft_id_2) assert isinstance(separation5, pd.DataFrame) assert separation5.loc[aircraft_id_2, aircraft_id_2] == 0
from pydodo import (change_altitude, change_heading, change_speed, aircraft_position, all_positions, reset_simulation, create_aircraft, async_change_altitude, batch) import time reset_simulation() aircraft_id = "TST1001" type = "B744" latitude = 0 longitude = 0 heading = 0 flight_level = 250 speed = 200 cmd = create_aircraft(aircraft_id = aircraft_id, type = type, latitude = latitude, longitude = longitude, heading = heading, flight_level = flight_level, speed = speed) t = time.time() print('Waiting...') while True: pos = all_positions() # print(format_runtime(time.time()-start))
def test_bluesky_response(): """Test that bluesky is running and responding before any other tests are run""" resp = reset_simulation() assert resp == True