You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					131 lines
				
				4.4 KiB
			
		
		
			
		
	
	
					131 lines
				
				4.4 KiB
			| 
								 
											2 years ago
										 
									 | 
							
								import copy
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								import json
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								import os
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								import random
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								from PIL import Image, ImageDraw, ImageFont
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from cereal import log, car
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from cereal.messaging import SubMaster
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from openpilot.common.basedir import BASEDIR
							 | 
						||
| 
								 | 
							
								from openpilot.common.params import Params
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								from openpilot.selfdrive.selfdrived.events import Alert, EVENTS, ET
							 | 
						||
| 
								 | 
							
								from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								AlertSize = log.SelfdriveState.AlertSize
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								OFFROAD_ALERTS_PATH = os.path.join(BASEDIR, "selfdrive/selfdrived/alerts_offroad.json")
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								# TODO: add callback alerts
							 | 
						||
| 
								 | 
							
								ALERTS = []
							 | 
						||
| 
								 | 
							
								for event_types in EVENTS.values():
							 | 
						||
| 
								 | 
							
								  for alert in event_types.values():
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    ALERTS.append(alert)
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								class TestAlerts:
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								  @classmethod
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def setup_class(cls):
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								    with open(OFFROAD_ALERTS_PATH) as f:
							 | 
						||
| 
								 | 
							
								      cls.offroad_alerts = json.loads(f.read())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      # Create fake objects for callback
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      cls.CS = car.CarState.new_message()
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      cls.CP = car.CarParams.new_message()
							 | 
						||
| 
								 | 
							
								      cfg = [c for c in CONFIGS if c.proc_name == 'controlsd'][0]
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								      cls.sm = SubMaster(cfg.pubs)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								  def test_events_defined(self):
							 | 
						||
| 
								 | 
							
								    # Ensure all events in capnp schema are defined in events.py
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    events = car.OnroadEvent.EventName.schema.enumerants
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    for name, e in events.items():
							 | 
						||
| 
								 | 
							
								      if not name.endswith("DEPRECATED"):
							 | 
						||
| 
								 | 
							
								        fail_msg = "%s @%d not in EVENTS" % (name, e)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								        assert e in EVENTS.keys(), fail_msg
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								  # ensure alert text doesn't exceed allowed width
							 | 
						||
| 
								 | 
							
								  def test_alert_text_length(self):
							 | 
						||
| 
								 | 
							
								    font_path = os.path.join(BASEDIR, "selfdrive/assets/fonts")
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    regular_font_path = os.path.join(font_path, "Inter-SemiBold.ttf")
							 | 
						||
| 
								 | 
							
								    bold_font_path = os.path.join(font_path, "Inter-Bold.ttf")
							 | 
						||
| 
								 | 
							
								    semibold_font_path = os.path.join(font_path, "Inter-SemiBold.ttf")
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    max_text_width = 2160 - 300  # full screen width is usable, minus sidebar
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    draw = ImageDraw.Draw(Image.new('RGB', (0, 0)))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fonts = {
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								      AlertSize.small: [ImageFont.truetype(semibold_font_path, 74)],
							 | 
						||
| 
								 | 
							
								      AlertSize.mid: [ImageFont.truetype(bold_font_path, 88),
							 | 
						||
| 
								 | 
							
								                      ImageFont.truetype(regular_font_path, 66)],
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								    for alert in ALERTS:
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      if not isinstance(alert, Alert):
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								        alert = alert(self.CP, self.CS, self.sm, metric=False, soft_disable_time=100, personality=log.LongitudinalPersonality.standard)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								      # for full size alerts, both text fields wrap the text,
							 | 
						||
| 
								 | 
							
								      # so it's unlikely that they  would go past the max width
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      if alert.alert_size in (AlertSize.none, AlertSize.full):
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								        continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      for i, txt in enumerate([alert.alert_text_1, alert.alert_text_2]):
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								        if i >= len(fonts[alert.alert_size]):
							 | 
						||
| 
								 | 
							
								          break
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								        font = fonts[alert.alert_size][i]
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								        left, _, right, _ = draw.textbbox((0, 0), txt, font)
							 | 
						||
| 
								 | 
							
								        width = right - left
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								        msg = f"type: {alert.alert_type} msg: {txt}"
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								        assert width <= max_text_width, msg
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								  def test_alert_sanity_check(self):
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    for event_types in EVENTS.values():
							 | 
						||
| 
								 | 
							
								      for event_type, a in event_types.items():
							 | 
						||
| 
								 | 
							
								        # TODO: add callback alerts
							 | 
						||
| 
								 | 
							
								        if not isinstance(a, Alert):
							 | 
						||
| 
								 | 
							
								          continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if a.alert_size == AlertSize.none:
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								          assert len(a.alert_text_1) == 0
							 | 
						||
| 
								 | 
							
								          assert len(a.alert_text_2) == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								        elif a.alert_size == AlertSize.small:
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								          assert len(a.alert_text_1) > 0
							 | 
						||
| 
								 | 
							
								          assert len(a.alert_text_2) == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								        elif a.alert_size == AlertSize.mid:
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								          assert len(a.alert_text_1) > 0
							 | 
						||
| 
								 | 
							
								          assert len(a.alert_text_2) > 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								        else:
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								          assert len(a.alert_text_1) > 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								        assert a.duration >= 0.
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								        if event_type not in (ET.WARNING, ET.PERMANENT, ET.PRE_ENABLE):
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								          assert a.creation_delay == 0.
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								  def test_offroad_alerts(self):
							 | 
						||
| 
								 | 
							
								    params = Params()
							 | 
						||
| 
								 | 
							
								    for a in self.offroad_alerts:
							 | 
						||
| 
								 | 
							
								      # set the alert
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								      alert = copy.copy(self.offroad_alerts[a])
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      set_offroad_alert(a, True)
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								      alert['extra'] = ''
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert json.dumps(alert) == params.get(a, encoding='utf8')
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								      # then delete it
							 | 
						||
| 
								 | 
							
								      set_offroad_alert(a, False)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert params.get(a) is None
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								  def test_offroad_alerts_extra_text(self):
							 | 
						||
| 
								 | 
							
								    params = Params()
							 | 
						||
| 
								 | 
							
								    for i in range(50):
							 | 
						||
| 
								 | 
							
								      # set the alert
							 | 
						||
| 
								 | 
							
								      a = random.choice(list(self.offroad_alerts))
							 | 
						||
| 
								 | 
							
								      alert = self.offroad_alerts[a]
							 | 
						||
| 
								 | 
							
								      set_offroad_alert(a, True, extra_text="a"*i)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								      written_alert = json.loads(params.get(a, encoding='utf8'))
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert "a"*i == written_alert['extra']
							 | 
						||
| 
								 | 
							
								      assert alert["text"] == written_alert['text']
							 |