"""Tiering decides what needs arming, so a misfiled command is a safety bug.""" import collections from mcbebop.protocol import xml_index from mcbebop.protocol.safety import ALWAYS_ALLOWED, tier_for from mcbebop.protocol.types import Direction, Tier MOTION = { # The aircraft itself. "ardrone3.Piloting.FlatTrim", "ardrone3.Piloting.TakeOff", "ardrone3.Piloting.PCMD", "ardrone3.Piloting.Landing", "ardrone3.Piloting.Emergency", "ardrone3.Piloting.NavigateHome", "ardrone3.Piloting.AutoTakeOffMode", "ardrone3.Piloting.moveBy", "ardrone3.Piloting.UserTakeOff", "ardrone3.Piloting.Circle", "ardrone3.Piloting.moveTo", "ardrone3.Piloting.CancelMoveTo", "ardrone3.Piloting.StartPilotedPOI", "ardrone3.Piloting.StopPilotedPOI", "ardrone3.Piloting.CancelMoveBy", "ardrone3.Piloting.StartPilotedPOIV2", "ardrone3.Animations.Flip", # Running a stored flight plan moves the whole mission. "common.Mavlink.Start", "common.Mavlink.Pause", "common.Mavlink.Stop", # Calibration asks a powered aircraft to rotate. "common.Calibration.MagnetoCalibration", "common.Calibration.PitotCalibration", "common.Animations.StartAnimation", "common.Animations.StopAnimation", "common.Animations.StopAllAnimations", } def test_motion_set_is_exactly_these(): tiered = {c.full_name for c in xml_index.all_commands() if c.tier is Tier.MOTION} assert tiered == MOTION def test_every_motion_command_is_sendable(): for name in MOTION: command = xml_index.get(name) assert command is not None, name assert command.direction is Direction.TO_DRONE, name def test_observe_is_the_two_dump_everything_commands(): sendable_observe = { c.full_name for c in xml_index.all_commands() if c.tier is Tier.OBSERVE and c.direction is Direction.TO_DRONE } assert sendable_observe == {"common.Common.AllStates", "common.Settings.AllSettings"} def test_envelope_covers_the_limit_and_radio_classes(): envelope = {c.full_name for c in xml_index.all_commands() if c.tier is Tier.ENVELOPE} for name in ( "ardrone3.PilotingSettings.MaxAltitude", "ardrone3.PilotingSettings.NoFlyOverMaxDistance", "ardrone3.SpeedSettings.MaxVerticalSpeed", "ardrone3.GPSSettings.SetHome", "ardrone3.Network.WifiScan", "ardrone3.NetworkSettings.WifiSelection", "common.Network.Disconnect", "common.WifiSettings.OutdoorSetting", "common.FlightPlanSettings.ReturnHomeOnDisconnect", "common.Settings.Country", "common.Settings.AutoCountry", "common.Settings.Reset", "common.Common.Reboot", "common.Factory.Reset", "common.OverHeat.SwitchOff", "common.Charger.SetMaxChargeRate", "common.Controller.isPiloting", ): assert name in envelope, name assert len(envelope) == 44 def test_config_is_the_harmless_remainder(): config = {c.full_name for c in xml_index.all_commands() if c.tier is Tier.CONFIG} assert len(config) == 31 for name in ( "ardrone3.MediaRecord.Picture", "ardrone3.MediaStreaming.VideoEnable", "ardrone3.PictureSettings.VideoFramerate", "ardrone3.Camera.Orientation", "common.Common.CurrentDate", "common.Settings.ProductName", "common.Headlights.intensity", ): assert name in config, name assert not any( c.direction is Direction.FROM_DRONE for c in xml_index.all_commands() if c.tier is Tier.CONFIG ) def test_sendable_tiers_account_for_every_to_drone_command(): counts = collections.Counter( c.tier for c in xml_index.all_commands() if c.direction is Direction.TO_DRONE ) assert counts[Tier.MOTION] == 25 assert counts[Tier.ENVELOPE] == 44 assert counts[Tier.OBSERVE] == 2 assert counts[Tier.CONFIG] == 31 assert sum(counts.values()) == 102 # 101 in the XML plus the injected FlatTrim def test_events_are_observe(): for command in xml_index.all_commands(): if command.direction is Direction.FROM_DRONE: assert command.tier is Tier.OBSERVE, command.full_name def test_always_allowed_are_the_two_that_end_a_flight(): assert frozenset({"ardrone3.Piloting.Landing", "ardrone3.Piloting.Emergency"}) == ALWAYS_ALLOWED for name in ALWAYS_ALLOWED: command = xml_index.get(name) assert command.tier is Tier.MOTION # locked by tier, exempted by name def test_tier_for_is_what_the_index_stamped(): for command in xml_index.all_commands(): assert tier_for(command) is command.tier