diff options
author | Robert Schütz <nix@dotlambda.de> | 2022-01-15 00:20:08 +0000 |
---|---|---|
committer | Robert Schütz <nix@dotlambda.de> | 2022-01-16 00:51:45 +0000 |
commit | 61265ec0b4176678aa776d901ace3d5191728b65 (patch) | |
tree | 2efb538761d0f5d7e65d8843721f11788d322726 /pkgs | |
parent | 6054fb82d5e5351d6432f57bd66de64723fe53ba (diff) |
home-assistant: outsource component tests
A component's tests can now be run by building home-assistant.tests.components.${component} Co-authored-by: Martin Weinelt <hexa@darmstadt.ccc.de>
Diffstat (limited to 'pkgs')
-rw-r--r-- | pkgs/servers/home-assistant/component-packages.nix | 567 | ||||
-rw-r--r-- | pkgs/servers/home-assistant/default.nix | 646 | ||||
-rwxr-xr-x | pkgs/servers/home-assistant/parse-requirements.py | 19 | ||||
-rw-r--r-- | pkgs/servers/home-assistant/patches/tests-mock-source-ip.patch | 4 | ||||
-rw-r--r-- | pkgs/servers/home-assistant/tests.nix | 69 | ||||
-rw-r--r-- | pkgs/top-level/all-packages.nix | 2 |
6 files changed, 680 insertions, 627 deletions
diff --git a/pkgs/servers/home-assistant/component-packages.nix b/pkgs/servers/home-assistant/component-packages.nix index 1a24fc7504ebe..aab639140e5ff 100644 --- a/pkgs/servers/home-assistant/component-packages.nix +++ b/pkgs/servers/home-assistant/component-packages.nix @@ -725,7 +725,7 @@ "rpi_gpio" = ps: with ps; [ ]; # missing inputs: RPi.GPIO "rpi_gpio_pwm" = ps: with ps; [ ]; # missing inputs: pwmled "rpi_pfio" = ps: with ps; [ ]; # missing inputs: pifacecommon pifacedigitalio - "rpi_power" = ps: with ps; [ ]; # missing inputs: rpi-bad-power + "rpi_power" = ps: with ps; [ rpi-bad-power ]; "rpi_rf" = ps: with ps; [ ]; # missing inputs: RPi.GPIO rpi-rf "rss_feed_template" = ps: with ps; [ aiohttp-cors ]; "rtorrent" = ps: with ps; [ ]; @@ -1018,4 +1018,569 @@ "zwave" = ps: with ps; [ homeassistant-pyozw pydispatcher ]; "zwave_js" = ps: with ps; [ aiohttp-cors pyserial pyudev zwave-js-server-python ]; }; + # components listed in tests/components for which all dependencies are packaged + supportedComponentsWithTests = [ + "abode" + "accuweather" + "acmeda" + "adax" + "adguard" + "advantage_air" + "aemet" + "agent_dvr" + "air_quality" + "airly" + "airnow" + "airthings" + "airtouch4" + "airvisual" + "alarm_control_panel" + "alarmdecoder" + "alert" + "alexa" + "almond" + "ambee" + "amberelectric" + "ambiclimate" + "ambient_station" + "analytics" + "androidtv" + "apache_kafka" + "api" + "apple_tv" + "apprise" + "aprs" + "arcam_fmj" + "arlo" + "asuswrt" + "atag" + "august" + "aurora" + "auth" + "automation" + "awair" + "aws" + "axis" + "azure_devops" + "azure_event_hub" + "balboa" + "bayesian" + "binary_sensor" + "blackbird" + "blebox" + "blink" + "blueprint" + "bluetooth_le_tracker" + "bmw_connected_drive" + "bond" + "bosch_shc" + "braviatv" + "broadlink" + "brother" + "bsblan" + "buienradar" + "button" + "caldav" + "calendar" + "camera" + "canary" + "cast" + "cert_expiry" + "climacell" + "climate" + "cloud" + "cloudflare" + "color_extractor" + "comfoconnect" + "command_line" + "compensation" + "config" + "configurator" + "control4" + "conversation" + "coolmaster" + "coronavirus" + "counter" + "cover" + "crownstone" + "daikin" + "darksky" + "datadog" + "debugpy" + "deconz" + "default_config" + "demo" + "denonavr" + "derivative" + "device_automation" + "device_sun_light_trigger" + "device_tracker" + "devolo_home_control" + "devolo_home_network" + "dexcom" + "dhcp" + "dialogflow" + "directv" + "discovery" + "dlna_dmr" + "doorbird" + "dsmr" + "dte_energy_bridge" + "duckdns" + "dunehd" + "eafm" + "ecobee" + "econet" + "efergy" + "elgato" + "elkm1" + "emonitor" + "emulated_hue" + "emulated_kasa" + "emulated_roku" + "energy" + "enocean" + "enphase_envoy" + "environment_canada" + "epson" + "esphome" + "everlights" + "evil_genius_labs" + "ezviz" + "faa_delays" + "facebook" + "facebox" + "fail2ban" + "fan" + "feedreader" + "ffmpeg" + "fido" + "file" + "filesize" + "filter" + "fireservicerota" + "firmata" + "fjaraskupan" + "flick_electric" + "flipr" + "flo" + "flume" + "flunearyou" + "flux" + "flux_led" + "folder" + "folder_watcher" + "foobot" + "forecast_solar" + "foscam" + "freebox" + "freedns" + "freedompro" + "fritz" + "fritzbox" + "fritzbox_callmonitor" + "fronius" + "frontend" + "garages_amsterdam" + "gdacs" + "generic" + "generic_hygrostat" + "generic_thermostat" + "geo_json_events" + "geo_location" + "geo_rss_events" + "geofency" + "geonetnz_quakes" + "geonetnz_volcano" + "gios" + "glances" + "goalzero" + "gogogate2" + "google" + "google_assistant" + "google_domains" + "google_pubsub" + "google_translate" + "google_travel_time" + "google_wifi" + "gpslogger" + "graphite" + "gree" + "group" + "growatt_server" + "guardian" + "habitica" + "hangouts" + "harmony" + "hassio" + "hddtemp" + "heos" + "here_travel_time" + "hisense_aehw4a1" + "history" + "history_stats" + "hive" + "hlk_sw16" + "home_connect" + "home_plus_control" + "homeassistant" + "homekit" + "homekit_controller" + "homematic" + "homematicip_cloud" + "honeywell" + "html5" + "http" + "huawei_lte" + "hue" + "huisbaasje" + "humidifier" + "hunterdouglas_powerview" + "hvv_departures" + "hyperion" + "ialarm" + "iaqualink" + "icloud" + "ifttt" + "ign_sismologia" + "image" + "image_processing" + "imap_email_content" + "influxdb" + "input_boolean" + "input_datetime" + "input_number" + "input_select" + "input_text" + "insteon" + "integration" + "intent" + "intent_script" + "ios" + "iotawatt" + "ipma" + "ipp" + "iqvia" + "islamic_prayer_times" + "isy994" + "izone" + "jellyfin" + "jewish_calendar" + "juicenet" + "keenetic_ndms2" + "kira" + "kmtronic" + "knx" + "kodi" + "konnected" + "kraken" + "kulersky" + "lastfm" + "lcn" + "light" + "litterrobot" + "local_file" + "local_ip" + "locative" + "lock" + "logbook" + "logentries" + "logger" + "london_air" + "lookin" + "lovelace" + "luftdaten" + "lutron_caseta" + "lyric" + "mailbox" + "manual" + "manual_mqtt" + "maxcube" + "mazda" + "media_player" + "media_source" + "melcloud" + "meraki" + "met" + "met_eireann" + "meteoclimatic" + "mhz19" + "microsoft_face" + "microsoft_face_detect" + "microsoft_face_identify" + "mikrotik" + "mill" + "min_max" + "minecraft_server" + "minio" + "mobile_app" + "modbus" + "modem_callerid" + "modern_forms" + "mold_indicator" + "moon" + "motion_blinds" + "motioneye" + "mqtt" + "mqtt_eventstream" + "mqtt_json" + "mqtt_room" + "mqtt_statestream" + "mullvad" + "mutesync" + "my" + "myq" + "mysensors" + "mythicbeastsdns" + "nam" + "namecheapdns" + "nanoleaf" + "neato" + "ness_alarm" + "nest" + "netatmo" + "network" + "nexia" + "nightscout" + "no_ip" + "notify" + "notion" + "nsw_rural_fire_service_feed" + "nuki" + "number" + "nws" + "nx584" + "octoprint" + "omnilogic" + "onboarding" + "ondilo_ico" + "openalpr_cloud" + "openalpr_local" + "openerz" + "opengarage" + "openhardwaremonitor" + "opentherm_gw" + "openuv" + "openweathermap" + "opnsense" + "ovo_energy" + "owntracks" + "ozw" + "p1_monitor" + "panel_custom" + "panel_iframe" + "persistent_notification" + "person" + "philips_js" + "pi_hole" + "picnic" + "ping" + "plaato" + "plant" + "plex" + "plugwise" + "point" + "poolsense" + "profiler" + "prometheus" + "prosegur" + "proximity" + "push" + "pushbullet" + "pvpc_hourly_pricing" + "python_script" + "qld_bushfire" + "rachio" + "radarr" + "rainforest_eagle" + "rainmachine" + "random" + "rdw" + "recollect_waste" + "recorder" + "reddit" + "remote" + "renault" + "rest" + "rest_command" + "rflink" + "rfxtrx" + "ridwell" + "ring" + "risco" + "rituals_perfume_genie" + "rmvtransport" + "roku" + "roomba" + "roon" + "rpi_power" + "rss_feed_template" + "ruckus_unleashed" + "safe_mode" + "samsungtv" + "scene" + "screenlogic" + "script" + "search" + "season" + "select" + "sense" + "sensor" + "sentry" + "seventeentrack" + "sharkiq" + "shell_command" + "shelly" + "shopping_list" + "sia" + "sigfox" + "sighthound" + "simplisafe" + "simulated" + "siren" + "slack" + "sleepiq" + "sma" + "smappee" + "smart_meter_texas" + "smarthab" + "smartthings" + "smarttub" + "smhi" + "smtp" + "snips" + "solaredge" + "solarlog" + "soma" + "somfy" + "somfy_mylink" + "sonarr" + "songpal" + "sonos" + "soundtouch" + "spaceapi" + "spc" + "speedtestdotnet" + "spider" + "spotify" + "sql" + "squeezebox" + "srp_energy" + "ssdp" + "starline" + "startca" + "statistics" + "statsd" + "stream" + "stt" + "subaru" + "sun" + "surepetcare" + "switch" + "switchbot" + "switcher_kis" + "syncthing" + "syncthru" + "synology_dsm" + "system_bridge" + "system_health" + "system_log" + "tado" + "tag" + "tailscale" + "tasmota" + "tcp" + "telegram" + "tellduslive" + "template" + "tesla_wall_connector" + "threshold" + "tibber" + "tile" + "time_date" + "timer" + "tod" + "tolo" + "tomato" + "toon" + "totalconnect" + "tplink" + "traccar" + "trace" + "tractive" + "tradfri" + "trafikverket_weatherstation" + "transmission" + "transport_nsw" + "trend" + "tts" + "tuya" + "twentemilieu" + "twilio" + "twinkly" + "twitch" + "uk_transport" + "unifi" + "unifi_direct" + "universal" + "upb" + "upcloud" + "updater" + "upnp" + "uptime" + "uptimerobot" + "usb" + "usgs_earthquakes_feed" + "utility_meter" + "uvc" + "vacuum" + "velbus" + "venstar" + "vera" + "verisure" + "version" + "vesync" + "vicare" + "vilfo" + "vizio" + "vlc_telnet" + "voicerss" + "volumio" + "vultr" + "wake_on_lan" + "wallbox" + "water_heater" + "watttime" + "waze_travel_time" + "weather" + "webhook" + "webostv" + "websocket_api" + "wemo" + "whirlpool" + "wiffi" + "wilight" + "wled" + "workday" + "worldclock" + "wsdot" + "xbox" + "xiaomi" + "xiaomi_aqara" + "xiaomi_miio" + "yale_smart_alarm" + "yamaha" + "yamaha_musiccast" + "yandex_transport" + "yandextts" + "yeelight" + "youless" + "zeroconf" + "zerproc" + "zha" + "zodiac" + "zone" + "zwave" + "zwave_js" + ]; } diff --git a/pkgs/servers/home-assistant/default.nix b/pkgs/servers/home-assistant/default.nix index 1a67003bdce48..1cf23984adb5e 100644 --- a/pkgs/servers/home-assistant/default.nix +++ b/pkgs/servers/home-assistant/default.nix @@ -1,5 +1,6 @@ { stdenv , lib +, callPackage , fetchFromGitHub , fetchpatch , python3 @@ -157,7 +158,7 @@ let }); }; - py = python3.override { + python = python3.override { # Put packageOverrides at the start so they are applied after defaultOverrides packageOverrides = lib.foldr lib.composeExtensions (self: super: { }) ([ packageOverrides ] ++ defaultOverrides); }; @@ -166,22 +167,24 @@ let availableComponents = builtins.attrNames componentPackages.components; - getPackages = component: builtins.getAttr component componentPackages.components; + inherit (componentPackages) supportedComponentsWithTests; - componentBuildInputs = lib.concatMap (component: getPackages component py.pkgs) extraComponents; + getPackages = component: componentPackages.components.${component}; + + componentBuildInputs = lib.concatMap (component: getPackages component python.pkgs) extraComponents; # Ensure that we are using a consistent package set - extraBuildInputs = extraPackages py.pkgs; + extraBuildInputs = extraPackages python.pkgs; # Don't forget to run parse-requirements.py after updating hassVersion = "2021.12.9"; -in with py.pkgs; buildPythonApplication rec { +in python.pkgs.buildPythonApplication rec { pname = "homeassistant"; version = assert (componentPackages.version == hassVersion); hassVersion; # check REQUIRED_PYTHON_VER in homeassistant/const.py - disabled = pythonOlder "3.8"; + disabled = python.pythonOlder "3.8"; # don't try and fail to strip 6600+ python files, it takes minutes! dontStrip = true; @@ -217,7 +220,7 @@ in with py.pkgs; buildPythonApplication rec { substituteInPlace tests/test_config.py --replace '"/usr"' '"/build/media"' ''; - propagatedBuildInputs = [ + propagatedBuildInputs = with python.pkgs; [ # Only packages required in setup.py aiohttp astral @@ -253,9 +256,10 @@ in with py.pkgs; buildPythonApplication rec { # upstream only tests on Linux, so do we. doCheck = stdenv.isLinux; - checkInputs = [ + checkInputs = with python.pkgs; [ # test infrastructure (selectively from requirement_test.txt) freezegun + jsonpickle pytest-aiohttp pytest-freezegun pytest-mock @@ -264,541 +268,15 @@ in with py.pkgs; buildPythonApplication rec { pytest-xdist pytestCheckHook requests-mock - stdlib-list - jsonpickle respx + stdlib-list + tqdm # required by tests/auth/mfa_modules pyotp - ] ++ lib.concatMap (component: getPackages component py.pkgs) componentTests; - - # We can reasonably test components that don't communicate with any network - # services. Before adding new components to this list make sure we have all - # its dependencies packaged and listed in ./component-packages.nix. - componentTests = [ - "abode" - "accuweather" - "acmeda" - "adguard" - "advantage_air" - "aemet" - "agent_dvr" - "air_quality" - "airly" - "airnow" - "airthings" - "airvisual" - "alarm_control_panel" - "alarmdecoder" - "alert" - "alexa" - "almond" - "ambiclimate" - "ambient_station" - "analytics" - "androidtv" - "apache_kafka" - "api" - "apple_tv" - "apprise" - "aprs" - "arcam_fmj" - "arlo" - "asuswrt" - "atag" - "august" - "aurora" - "auth" - "automation" - "awair" - "aws" - "axis" - "azure_devops" - "azure_event_hub" - "bayesian" - "binary_sensor" - "blackbird" - "blebox" - "blink" - "blueprint" - "bluetooth_le_tracker" - "bmw_connected_drive" - "bond" - "bosch_shc" - "braviatv" - "broadlink" - "brother" - "bsblan" - "buienradar" - "caldav" - "calendar" - "camera" - "canary" - "cast" - "cert_expiry" - "climacell" - "climate" - "cloud" - "cloudflare" - "color_extractor" - "comfoconnect" - "command_line" - "compensation" - "config" - "configurator" - "control4" - "conversation" - "coolmaster" - "coronavirus" - "counter" - "cover" - "daikin" - "darksky" - "datadog" - "deconz" + ] ++ lib.concatMap (component: getPackages component python.pkgs) [ + # some components are needed even if tests in tests/components are disabled "default_config" - "demo" - "denonavr" - "derivative" - "device_automation" - "device_sun_light_trigger" - "device_tracker" - "devolo_home_control" - "dexcom" - "dhcp" - "dialogflow" - "directv" - "discovery" - "doorbird" - "dsmr" - "dte_energy_bridge" - "duckdns" - "dunehd" - "eafm" - "ecobee" - "econet" - "efergy" - "elgato" - "elkm1" - "emonitor" - "emulated_hue" - "emulated_kasa" - "emulated_roku" - "enocean" - "enphase_envoy" - "epson" - "esphome" - "everlights" - "ezviz" - "faa_delays" - "facebook" - "facebox" - "fail2ban" - "fan" - "feedreader" - "ffmpeg" - "fido" - "file" - "filesize" - "filter" - "fireservicerota" - "firmata" - "fjaraskupan" - "flick_electric" - "flipr" - "flo" - "flume" - "flunearyou" - "flux" - "folder" - "folder_watcher" - "foobot" - "foscam" - "freebox" - "freedns" - "fritz" - "fritzbox" - "fritzbox_callmonitor" - "frontend" - "garages_amsterdam" - "gdacs" - "generic" - "generic_thermostat" - "geo_json_events" - "geo_location" - "geo_rss_events" - "geofency" - "geonetnz_quakes" - "geonetnz_volcano" - "gios" - # updated to incompatible version and overriding is annoying because of async_timeout<4 pin - # "glances" - "goalzero" - "gogogate2" - "google" - "google_assistant" - "google_domains" - "google_pubsub" - "google_translate" - "google_travel_time" - "google_wifi" - "gpslogger" - "graphite" - "gree" - "group" - "growatt_server" - "guardian" - "habitica" - "hangouts" - "harmony" - "hassio" - "hddtemp" - "heos" - "here_travel_time" - "hisense_aehw4a1" - "history" - "history_stats" - "hive" - "hlk_sw16" - "home_connect" - "home_plus_control" - "homeassistant" - # disable homekit tests because they fail in the network component - #"homekit" - "homekit_controller" - "homematic" - "homematicip_cloud" - "honeywell" - "html5" - "http" - "huawei_lte" "hue" - "huisbaasje" - "humidifier" - "hunterdouglas_powerview" - "hvv_departures" - "hyperion" - "ialarm" - "iaqualink" - "icloud" - "ifttt" - "ign_sismologia" - "image" - "image_processing" - "imap_email_content" - "influxdb" - "input_boolean" - "input_datetime" - "input_number" - "input_select" - "input_text" - "insteon" - "integration" - "intent" - "intent_script" - "ios" - "ipma" - "ipp" - "iqvia" - "islamic_prayer_times" - "isy994" - "izone" - "jewish_calendar" - "juicenet" - "keenetic_ndms2" - "kira" - "kmtronic" - "knx" - "kodi" - "konnected" - "kraken" - "kulersky" - "lastfm" - "lcn" - "light" - "litterrobot" - "local_file" - "local_ip" - "locative" - "lock" - "logbook" - "logentries" - "logger" - "london_air" - "lovelace" - "luftdaten" - "lutron_caseta" - "lyric" - "mailbox" - "manual" - "manual_mqtt" - "maxcube" - "mazda" - "media_player" - "media_source" - "melcloud" - "meraki" - "met" - "met_eireann" - "meteoclimatic" - "mhz19" - "microsoft_face" - "microsoft_face_detect" - "microsoft_face_identify" - "mikrotik" - "mill" - "min_max" - "minecraft_server" - "minio" - "mobile_app" - "modbus" - "mold_indicator" - "moon" - "motion_blinds" - "motioneye" - "mqtt" - "mqtt_eventstream" - "mqtt_json" - "mqtt_room" - "mqtt_statestream" - "mullvad" - "mutesync" - "my" - "myq" - "mysensors" - "mythicbeastsdns" - "nam" - "namecheapdns" - "neato" - "ness_alarm" - # python-nest has an unfree license, this prevents builds through ofborg - # "nest" - "netatmo" - "nexia" - "nightscout" - "no_ip" - "notify" - "notion" - "nsw_rural_fire_service_feed" - "nuki" - "number" - "nws" - "nx584" - "octoprint" - "omnilogic" - "onboarding" - "ondilo_ico" - "openalpr_cloud" - "openalpr_local" - "openerz" - "openhardwaremonitor" - "opentherm_gw" - "openuv" - "openweathermap" - "opnsense" - "ovo_energy" - "owntracks" - "ozw" - "p1_monitor" - "panel_custom" - "panel_iframe" - "persistent_notification" - "person" - "philips_js" - "pi_hole" - "picnic" - "ping" - "plaato" - "plant" - "plex" - "plugwise" - "point" - "poolsense" - "profiler" - "prometheus" - "proximity" - "push" - "pushbullet" - "pvpc_hourly_pricing" - "python_script" - "qld_bushfire" - "rachio" - "radarr" - "rainmachine" - "random" - "recollect_waste" - "recorder" - "reddit" - "remote" - "renault" - "rest" - "rest_command" - "rflink" - "rfxtrx" - "ring" - "risco" - "rituals_perfume_genie" - "rmvtransport" - "roku" - "roomba" - "roon" - "rss_feed_template" - "ruckus_unleashed" - "safe_mode" - "samsungtv" - "scene" - "screenlogic" - "script" - "search" - "season" - "sense" - "sensor" - "sentry" - "sharkiq" - "shell_command" - "shelly" - "shopping_list" - "sia" - "sigfox" - "sighthound" - "simplisafe" - "simulated" - "slack" - "sleepiq" - "sma" - "smappee" - "smart_meter_texas" - "smarthab" - "smartthings" - "smarttub" - "smhi" - "smtp" - "snips" - "solaredge" - "soma" - "somfy" - "somfy_mylink" - "sonarr" - "songpal" - # disable sonos components test because they rely on ssdp, which doesn't work in our sandbox - # "sonos" - "soundtouch" - "spaceapi" - "spc" - "speedtestdotnet" - "spider" - "spotify" - "sql" - "squeezebox" - "srp_energy" - "ssdp" - "starline" - "startca" - "statistics" - "statsd" - "stream" - "stt" - "subaru" - "sun" - "surepetcare" - "switch" - "switcher_kis" - "syncthing" - "syncthru" - "synology_dsm" - "system_health" - "system_log" - "tado" - "tag" - "tasmota" - "tcp" - "telegram" - "tellduslive" - "template" - "threshold" - "tibber" - "tile" - "time_date" - "timer" - "tod" - "tomato" - "toon" - "totalconnect" - "tplink" - "traccar" - "trace" - "tradfri" - "transmission" - "transport_nsw" - "trend" - "tts" - "tuya" - "twentemilieu" - "twilio" - "twinkly" - "twitch" - "uk_transport" - "unifi" - "unifi_direct" - "universal" - "upb" - "upcloud" - "updater" - # disabled, because it tries to join a multicast group and fails to find a usable network interface - # "upnp" - "uptime" - "uptimerobot" - "usgs_earthquakes_feed" - "utility_meter" - "uvc" - "vacuum" - "velbus" - # disabled, because it includes onewire component tests, for which we lack p1wire dependency - # "venstar" - "vera" - "verisure" - "version" - "vesync" - "vilfo" - "vizio" - "vlc_telnet" - "voicerss" - "volumio" - "vultr" - "wake_on_lan" - "wallbox" - "water_heater" - "waze_travel_time" - "weather" - "webhook" - "webostv" - "websocket_api" - "wemo" - "wiffi" - "wilight" - "wled" - "workday" - "worldclock" - "wsdot" - "xbox" - "xiaomi" - "xiaomi_aqara" - # disabled, because we require cryptography>=35.0 for the miio package - # "xiaomi_miio" - "yamaha" - "yandex_transport" - "yandextts" - "yeelight" - "youless" - # disabled, because it tries to join a multicast group and fails to find a usable network interface - # "zeroconf" - "zerproc" - "zha" - "zodiac" - "zone" - "zwave" - "zwave_js" - ] ++ lib.optionals (builtins.any (s: s == stdenv.hostPlatform.system) debugpy.meta.platforms) [ - "debugpy" ]; pytestFlagsArray = [ @@ -811,120 +289,46 @@ in with py.pkgs; buildPythonApplication rec { "--only-rerun RuntimeError" # enable full variable printing on error "--showlocals" - # here_travel_time/test_sensor.py: Tries to access HERE API: herepy.error.HEREError: Error occured on __get - "--deselect tests/components/here_travel_time/test_sensor.py::test_invalid_credentials" - # screenlogic/test_config_flow.py: Tries to send out UDP broadcasts - "--deselect tests/components/screenlogic/test_config_flow.py::test_form_cannot_connect" - # abode/test_camera.py: Race condition in pickle file creationg - "--deselect tests/components/abode/test_camera.py::test_camera_off" - # asuswrt/test_config_flow.py: Sandbox network limitations, fails with unexpected error - "--deselect tests/components/asuswrt/test_config_flow.py::test_on_connect_failed" - # shelly/test_config_flow.py: Tries to join multicast group - "--deselect tests/components/shelly/test_config_flow.py::test_form" - "--deselect tests/components/shelly/test_config_flow.py::test_title_without_name" - "--deselect tests/components/shelly/test_config_flow.py::test_form_auth" - "--deselect tests/components/shelly/test_config_flow.py::test_form_errors_test_connection" - "--deselect tests/components/shelly/test_config_flow.py::test_user_setup_ignored_device" - "--deselect tests/components/shelly/test_config_flow.py::test_form_auth_errors_test_connection" - "--deselect tests/components/shelly/test_config_flow.py::test_form_auth_errors_test_connection" - "--deselect tests/components/shelly/test_config_flow.py::test_form_auth_errors_test_connection" - "--deselect tests/components/shelly/test_config_flow.py::test_zeroconf" - "--deselect tests/components/shelly/test_config_flow.py::test_zeroconf_sleeping_device" - "--deselect tests/components/shelly/test_config_flow.py::test_zeroconf_sleeping_device_error" - "--deselect tests/components/shelly/test_config_flow.py::test_zeroconf_sleeping_device_error" - "--deselect tests/components/shelly/test_config_flow.py::test_zeroconf_require_auth" - # prometheus/test_init.py: Spurious AssertionError regarding humidifier_target_humidity_percent metric - "--deselect tests/components/prometheus/test_init.py::test_view" - # smhi/test_init.py: Tries to fetch data from the network: socket.gaierror: [Errno -2] Name or service not known - "--deselect tests/components/smhi/test_init.py::test_remove_entry" - # wallbox/test_config_flow.py: Tries to connect to api.wall-box.cim: Failed to establish a new connection: [Errno -2] Name or service not known - "--deselect tests/components/wallbox/test_config_flow.py::test_form_invalid_auth" - "--deselect tests/components/wallbox/test_config_flow.py::test_form_cannot_connect" - # default_config/test_init.py: Tries to check for updates and fails ungracefully without network access - "--deselect tests/components/default_config/test_init.py::test_setup" - # local_ip/test_{init,config_flow}.py: tries to lookup a route towards a multicast address and fails - "--deselect tests/components/local_ip/test_init.py::test_basic_setup" - "--deselect tests/components/local_ip/test_config_flow.py::test_config_flow" - # netatmo/test_select.py: NoneType object has no attribute state - "--deselect tests/components/netatmo/test_select.py::test_select_schedule_thermostats" - # wemo/test_sensor.py: KeyError for various power attributes - "--deselect tests/components/wemo/test_sensor.py::TestInsightTodayEnergy::test_state_unavailable" - "--deselect tests/components/wemo/test_sensor.py::TestInsightCurrentPower::test_state_unavailable" # helpers/test_system_info.py: AssertionError: assert 'Unknown' == 'Home Assistant Container' "--deselect tests/helpers/test_system_info.py::test_container_installationtype" # tests are located in tests/ "tests" - # dynamically add packages required for component tests - ] ++ map (component: "tests/components/" + component) componentTests; + ]; disabledTestPaths = [ # don't bulk test all components "tests/components" # pyotp since v2.4.0 complains about the short mock keys, hass pins v2.3.0 "tests/auth/mfa_modules/test_notify.py" - # emulated_hue/test_upnp.py: Tries to establish the public ipv4 address - "tests/components/emulated_hue/test_upnp.py" - # tado/test_{climate,water_heater}.py: Tries to connect to my.tado.com - "tests/components/tado/test_climate.py" - "tests/components/tado/test_water_heater.py" ]; disabledTests = [ # AssertionError: assert 1 == 0 - "test_error_posted_as_event" "test_merge" - # ModuleNotFoundError: No module named 'pyqwikswitch' - "test_merge_id_schema" - # keyring.errors.NoKeyringError: No recommended backend was available. - "test_secrets_from_unrelated_fails" - "test_secrets_credstash" - # generic/test_camera.py: AssertionError: 500 == 200 - "test_fetching_without_verify_ssl" - "test_fetching_url_with_verify_ssl" - # util/test_package.py: AssertionError on package.is_installed('homeassistant>=999.999.999') - "test_check_package_version_does_not_match" - # homeassistant/util/thread.py:51: SystemError - "test_executor_shutdown_can_interrupt_threads" - # {'theme_color': '#03A9F4'} != {'theme_color': 'blue'} - "test_webhook_handle_get_config" - # onboarding tests rpi_power component, for which we are lacking rpi_bad_power library - "test_onboarding_core_sets_up_rpi_power" - "test_onboarding_core_no_rpi_power" - # hue/test_sensor_base.py: Race condition when counting events - "test_hue_events" - # august/test_lock.py: AssertionError: assert 'unlocked' == 'locked' / assert 'off' == 'on' - "test_lock_update_via_pubnub" - "test_door_sense_update_via_pubnub" # Tests are flaky "test_config_platform_valid" - "test_hls_stream" ]; preCheck = '' export HOME="$TEMPDIR" - patch -p1 < ${./patches/tests-mock-source-ip.patch} - # the tests require the existance of a media dir mkdir /build/media # put ping binary into PATH, e.g. for wake_on_lan tests export PATH=${inetutils}/bin:$PATH - - # error out when component test directory is missing, otherwise hidden by xdist execution :( - for component in ${lib.concatStringsSep " " (map lib.escapeShellArg componentTests)}; do - test -d "tests/components/$component" || { - >2& echo "ERROR: Tests for component '$component' were enabled, but they do not exist!" - exit 1 - } - done ''; passthru = { - inherit availableComponents extraComponents; - python = py; + inherit + availableComponents + extraComponents + getPackages + python + supportedComponentsWithTests; tests = { - inherit (nixosTests) home-assistant; + nixos = nixosTests.home-assistant; + components = callPackage ./tests.nix { }; }; }; diff --git a/pkgs/servers/home-assistant/parse-requirements.py b/pkgs/servers/home-assistant/parse-requirements.py index 4a2c42ff370c6..fbe46b2377876 100755 --- a/pkgs/servers/home-assistant/parse-requirements.py +++ b/pkgs/servers/home-assistant/parse-requirements.py @@ -62,6 +62,7 @@ def get_version(): def parse_components(version: str = "master"): components = {} + components_with_tests = [] with tempfile.TemporaryDirectory() as tmp: with urlopen( f"https://github.com/home-assistant/home-assistant/archive/{version}.tar.gz" @@ -69,9 +70,13 @@ def parse_components(version: str = "master"): tarfile.open(fileobj=BytesIO(response.read())).extractall(tmp) # Use part of a script from the Home Assistant codebase core_path = os.path.join(tmp, f"core-{version}") + + for entry in os.scandir(os.path.join(core_path, "tests/components")): + if entry.is_dir(): + components_with_tests.append(entry.name) + sys.path.append(core_path) from script.hassfest.model import Integration - integrations = Integration.load_dir( pathlib.Path( os.path.join(core_path, "homeassistant/components") @@ -81,7 +86,8 @@ def parse_components(version: str = "master"): integration = integrations[domain] if not integration.disabled: components[domain] = integration.manifest - return components + + return components, components_with_tests # Recursively get the requirements of a component and its dependencies @@ -162,7 +168,7 @@ def main() -> None: packages = dump_packages() version = get_version() print("Generating component-packages.nix for version {}".format(version)) - components = parse_components(version=version) + components, components_with_tests = parse_components(version=version) build_inputs = {} outdated = {} for component in sorted(components.keys()): @@ -205,6 +211,13 @@ def main() -> None: f.write(f" # missing inputs: {' '.join(missing)}") f.write("\n") f.write(" };\n") + f.write(" # components listed in tests/components for which all dependencies are packaged\n") + f.write(" supportedComponentsWithTests = [\n") + for component, deps in build_inputs.items(): + available, missing = deps + if len(missing) == 0 and component in components_with_tests: + f.write(f' "{component}"' + "\n") + f.write(" ];\n") f.write("}\n") supported_components = reduce(lambda n, c: n + (build_inputs[c][1] == []), diff --git a/pkgs/servers/home-assistant/patches/tests-mock-source-ip.patch b/pkgs/servers/home-assistant/patches/tests-mock-source-ip.patch index 4094d08ee7ff8..6812ee1915bb0 100644 --- a/pkgs/servers/home-assistant/patches/tests-mock-source-ip.patch +++ b/pkgs/servers/home-assistant/patches/tests-mock-source-ip.patch @@ -1,8 +1,8 @@ diff --git a/homeassistant/components/network/__init__.py b/homeassistant/components/network/__init__.py -index 7cc864727d..69333a5454 100644 +index b3ef88e7ab..b7a8471e1a 100644 --- a/homeassistant/components/network/__init__.py +++ b/homeassistant/components/network/__init__.py -@@ -26,7 +26,7 @@ async def async_get_source_ip( +@@ -30,7 +30,7 @@ async def async_get_source_ip( ) -> str: """Get the source ip for a target ip.""" adapters = await async_get_adapters(hass) diff --git a/pkgs/servers/home-assistant/tests.nix b/pkgs/servers/home-assistant/tests.nix new file mode 100644 index 0000000000000..8e552ed15e0b3 --- /dev/null +++ b/pkgs/servers/home-assistant/tests.nix @@ -0,0 +1,69 @@ +{ lib +, home-assistant +}: + +let + # some components' tests have additional dependencies + extraCheckInputs = with home-assistant.python.pkgs; { + alexa = [ ha-av ]; + camera = [ ha-av ]; + cloud = [ mutagen ]; + config = [ pydispatcher ]; + generic = [ ha-av ]; + google_translate = [ mutagen ]; + nest = [ ha-av ]; + onboarding = [ pymetno rpi-bad-power ]; + voicerss = [ mutagen ]; + yandextts = [ mutagen ]; + zha = [ pydeconz ]; + zwave_js = [ homeassistant-pyozw ]; + }; + + extraDisabledTestPaths = { + tado = [ + # tado/test_{climate,water_heater}.py: Tries to connect to my.tado.com + "tests/components/tado/test_climate.py" + "tests/components/tado/test_water_heater.py" + ]; + }; + + extraPytestFlagsArray = { + asuswrt = [ + # asuswrt/test_config_flow.py: Sandbox network limitations, fails with unexpected error + "--deselect tests/components/asuswrt/test_config_flow.py::test_on_connect_failed" + ]; + }; +in lib.listToAttrs (map (component: lib.nameValuePair component ( + home-assistant.overridePythonAttrs (old: { + pname = "homeassistant-test-${component}"; + + dontBuild = true; + dontInstall = true; + + checkInputs = old.checkInputs + ++ home-assistant.getPackages component home-assistant.python.pkgs + ++ extraCheckInputs.${component} or [ ]; + + disabledTestPaths = old.disabledTestPaths ++ extraDisabledTestPaths.${component} or [ ]; + + pytestFlagsArray = lib.remove "tests" old.pytestFlagsArray + ++ extraPytestFlagsArray.${component} or [ ] + ++ [ "tests/components/${component}" ]; + + preCheck = old.preCheck + lib.optionalString (component != "network") '' + patch -p1 < ${./patches/tests-mock-source-ip.patch} + ''; + + meta = old.meta // { + broken = lib.elem component [ + "airtouch4" + "glances" + "ridwell" + "venstar" + "yamaha_musiccast" + ]; + # upstream only tests on Linux, so do we. + platforms = lib.platforms.linux; + }; + }) +)) home-assistant.supportedComponentsWithTests) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index f6cb53114a478..052c68465ad2d 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -21064,6 +21064,8 @@ with pkgs; home-assistant-cli = callPackage ../servers/home-assistant/cli.nix { }; + home-assistant-component-tests = recurseIntoAttrs home-assistant.tests.components; + hqplayerd = callPackage ../servers/hqplayerd { }; https-dns-proxy = callPackage ../servers/dns/https-dns-proxy { }; |