home-assistant: enable comfoconnect tests
[NixPkgs.git] / pkgs / servers / home-assistant / default.nix
blobd02cc41ea28a2d6de66a753840dc07ee023fe340
1 { stdenv
2 , lib
3 , fetchFromGitHub
4 , python3
5 , nixosTests
7 # Look up dependencies of specified components in component-packages.nix
8 , extraComponents ? [ ]
10 # Additional packages to add to propagatedBuildInputs
11 , extraPackages ? ps: []
13 # Override Python packages using
14 # self: super: { pkg = super.pkg.overridePythonAttrs (oldAttrs: { ... }); }
15 # Applied after defaultOverrides
16 , packageOverrides ? self: super: {}
18 # Skip pip install of required packages on startup
19 , skipPip ? true }:
21 let
22   defaultOverrides = [
23     # Override the version of some packages pinned in Home Assistant's setup.py
25     # Pinned due to API changes in astral>=2.0, required by the sun/moon plugins
26     # https://github.com/home-assistant/core/issues/36636
27     (mkOverride "astral" "1.10.1"
28       "d2a67243c4503131c856cafb1b1276de52a86e5b8a1d507b7e08bee51cb67bf1")
30     # Pinned due to API changes in iaqualink>=2.0, remove after
31     # https://github.com/home-assistant/core/pull/48137 was merged
32     (self: super: {
33       iaqualink = super.iaqualink.overridePythonAttrs (oldAttrs: rec {
34         version = "0.3.4";
35         src = fetchFromGitHub {
36           owner = "flz";
37           repo = "iaqualink-py";
38           rev = "v${version}";
39           sha256 = "16mn6nd9x3hm6j6da99qhwbqs95hh8wx21r1h1m9csl76z77n9lh";
40         };
41         checkInputs = oldAttrs.checkInputs ++ [ python3.pkgs.asynctest ];
42       });
43     })
45     # Pinned due to API changes in pylilterbot>=2021.3.0
46     (self: super: {
47       pylitterbot = super.pylitterbot.overridePythonAttrs (oldAttrs: rec {
48         version = "2021.2.8";
49         src = fetchFromGitHub {
50           owner = "natekspencer";
51           repo = "pylitterbot";
52           rev = version;
53           sha256 = "142lhijm51v11cd0lhcfdnjdd143jxi2hjsrqdq0rrbbnmj6mymp";
54         };
55         # had no tests before 2021.3.0
56         doCheck = false;
57       });
58     })
60     # Pinned due to bug in ring-doorbell 0.7.0
61     # https://github.com/tchellomello/python-ring-doorbell/issues/240
62     (mkOverride "ring-doorbell" "0.6.2"
63       "fbd537722a27b3b854c26506d894b7399bb8dc57ff36083285971227a2d46560")
65     # hass-frontend does not exist in python3.pkgs
66     (self: super: {
67       hass-frontend = self.callPackage ./frontend.nix { };
68     })
69   ];
71   mkOverride = attrname: version: sha256:
72     self: super: {
73       ${attrname} = super.${attrname}.overridePythonAttrs (oldAttrs: {
74         inherit version;
75         src = oldAttrs.src.override {
76           inherit version sha256;
77         };
78       });
79     };
81   py = python3.override {
82     # Put packageOverrides at the start so they are applied after defaultOverrides
83     packageOverrides = lib.foldr lib.composeExtensions (self: super: { }) ([ packageOverrides ] ++ defaultOverrides);
84   };
86   componentPackages = import ./component-packages.nix;
88   availableComponents = builtins.attrNames componentPackages.components;
90   getPackages = component: builtins.getAttr component componentPackages.components;
92   componentBuildInputs = lib.concatMap (component: getPackages component py.pkgs) extraComponents;
94   # Ensure that we are using a consistent package set
95   extraBuildInputs = extraPackages py.pkgs;
97   # Don't forget to run parse-requirements.py after updating
98   hassVersion = "2021.4.3";
100 in with py.pkgs; buildPythonApplication rec {
101   pname = "homeassistant";
102   version = assert (componentPackages.version == hassVersion); hassVersion;
104   # check REQUIRED_PYTHON_VER in homeassistant/const.py
105   disabled = pythonOlder "3.8";
107   # don't try and fail to strip 6600+ python files, it takes minutes!
108   dontStrip = true;
110   inherit availableComponents;
112   # PyPI tarball is missing tests/ directory
113   src = fetchFromGitHub {
114     owner = "home-assistant";
115     repo = "core";
116     rev = version;
117     sha256 = "00jgnk8vssvk7mdnlijwddwaj56hs1hcyw83r1jqhn5nk5qj3b7q";
118   };
120   # leave this in, so users don't have to constantly update their downstream patch handling
121   patches = [
122   ];
124   postPatch = ''
125     substituteInPlace setup.py \
126       --replace "awesomeversion==21.2.3" "awesomeversion" \
127       --replace "bcrypt==3.1.7" "bcrypt" \
128       --replace "cryptography==3.3.2" "cryptography" \
129       --replace "pip>=8.0.3,<20.3" "pip" \
130       --replace "pytz>=2021.1" "pytz" \
131       --replace "pyyaml==5.4.1" "pyyaml" \
132       --replace "ruamel.yaml==0.15.100" "ruamel.yaml"
133     substituteInPlace tests/test_config.py --replace '"/usr"' '"/build/media"'
134   '';
136   propagatedBuildInputs = [
137     # Only packages required in setup.py + hass-frontend
138     aiohttp
139     astral
140     async-timeout
141     attrs
142     awesomeversion
143     bcrypt
144     certifi
145     ciso8601
146     cryptography
147     hass-frontend
148     httpx
149     jinja2
150     pip
151     pyjwt
152     python-slugify
153     pytz
154     pyyaml
155     requests
156     ruamel_yaml
157     voluptuous
158     voluptuous-serialize
159     yarl
160   ] ++ componentBuildInputs ++ extraBuildInputs;
162   makeWrapperArgs = lib.optional skipPip "--add-flags --skip-pip";
164   # upstream only tests on Linux, so do we.
165   doCheck = stdenv.isLinux;
167   checkInputs = [
168     # test infrastructure
169     asynctest
170     pytest-aiohttp
171     pytest-rerunfailures
172     pytest-xdist
173     pytestCheckHook
174     requests-mock
175     # component dependencies
176     pyotp
177     respx
178   ] ++ lib.concatMap (component: getPackages component py.pkgs) componentTests;
180   # We can reasonably test components that don't communicate with any network
181   # services. Before adding new components to this list make sure we have all
182   # its dependencies packaged and listed in ./component-packages.nix.
183   componentTests = [
184     "accuweather"
185     "airly"
186     "analytics"
187     "alert"
188     "api"
189     "auth"
190     "automation"
191     "axis"
192     "bayesian"
193     "binary_sensor"
194     "caldav"
195     "calendar"
196     "camera"
197     "cast"
198     "climate"
199     "cloud"
200     "comfoconnect"
201     "command_line"
202     "config"
203     "configurator"
204     "conversation"
205     "counter"
206     "cover"
207     "deconz"
208     "default_config"
209     "demo"
210     "derivative"
211     "device_automation"
212     "device_sun_light_trigger"
213     "device_tracker"
214     "devolo_home_control"
215     "dhcp"
216     "discovery"
217     "emulated_hue"
218     "esphome"
219     "fan"
220     "faa_delays"
221     "ffmpeg"
222     "file"
223     "filesize"
224     "filter"
225     "flux"
226     "folder"
227     "folder_watcher"
228     "freebox"
229     "fritzbox"
230     "fritzbox_callmonitor"
231     "frontend"
232     "generic"
233     "generic_thermostat"
234     "geo_json_events"
235     "geo_location"
236     "group"
237     "hddtemp"
238     "history"
239     "history_stats"
240     "home_plus_control"
241     "homekit"
242     "homekit_controller"
243     "homeassistant"
244     "homematic"
245     "homematicip_cloud"
246     "html5"
247     "http"
248     "hue"
249     "iaqualink"
250     "ifttt"
251     "image"
252     "image_processing"
253     "influxdb"
254     "input_boolean"
255     "input_datetime"
256     "input_text"
257     "input_number"
258     "input_select"
259     "intent"
260     "intent_script"
261     "ipp"
262     "kmtronic"
263     "kodi"
264     "light"
265     "litterrobot"
266     "local_file"
267     "local_ip"
268     "lock"
269     "logbook"
270     "logentries"
271     "logger"
272     "lovelace"
273     "manual"
274     "manual_mqtt"
275     "mazda"
276     "media_player"
277     "media_source"
278     "met"
279     "minecraft_server"
280     "mobile_app"
281     "modbus"
282     "moon"
283     "mqtt"
284     "mqtt_eventstream"
285     "mqtt_json"
286     "mqtt_room"
287     "mqtt_statestream"
288     "mullvad"
289     "notify"
290     "notion"
291     "number"
292     "omnilogic"
293     "ozw"
294     "panel_custom"
295     "panel_iframe"
296     "persistent_notification"
297     "person"
298     "plaato"
299     "prometheus"
300     "proximity"
301     "push"
302     "python_script"
303     "random"
304     "recorder"
305     "rest"
306     "rest_command"
307     "rituals_perfume_genie"
308     "rmvtransport"
309     "rss_feed_template"
310     "safe_mode"
311     "scene"
312     "screenlogic"
313     "script"
314     "search"
315     "shell_command"
316     "shopping_list"
317     "simplisafe"
318     "simulated"
319     "sma"
320     "sensor"
321     "smarttub"
322     "smtp"
323     "smappee"
324     "solaredge"
325     "sonos"
326     "spotify"
327     "sql"
328     "ssdp"
329     "stream"
330     "subaru"
331     "sun"
332     "switch"
333     "system_health"
334     "system_log"
335     "tag"
336     "tasmota"
337     "tcp"
338     "template"
339     "threshold"
340     "time_date"
341     "timer"
342     "tod"
343     "trace"
344     "tts"
345     "universal"
346     "updater"
347     "upnp"
348     "uptime"
349     "vacuum"
350     "verisure"
351     "weather"
352     "webhook"
353     "websocket_api"
354     "wled"
355     "workday"
356     "worldclock"
357     "zeroconf"
358     "zha"
359     "zone"
360     "zwave"
361   ];
363   pytestFlagsArray = [
364     # limit amout of runners to reduce race conditions
365     "-n auto"
366     # retry racy tests that end in "RuntimeError: Event loop is closed"
367     "--reruns 3"
368     "--only-rerun RuntimeError"
369     # assign tests grouped by file to workers
370     "--dist loadfile"
371     # tests are located in tests/
372     "tests"
373     # screenlogic/test_config_flow.py: Tries to send out UDP broadcasts
374     "--deselect tests/components/screenlogic/test_config_flow.py::test_form_cannot_connect"
375     # dynamically add packages required for component tests
376   ] ++ map (component: "tests/components/" + component) componentTests;
378   disabledTestPaths = [
379     # don't bulk test all components
380     "tests/components"
381     # pyotp since v2.4.0 complains about the short mock keys, hass pins v2.3.0
382     "tests/auth/mfa_modules/test_notify.py"
383   ];
385   disabledTests = [
386     # AssertionError: assert 1 == 0
387     "test_error_posted_as_event"
388     "test_merge"
389     # ModuleNotFoundError: No module named 'pyqwikswitch'
390     "test_merge_id_schema"
391     # keyring.errors.NoKeyringError: No recommended backend was available.
392     "test_secrets_from_unrelated_fails"
393     "test_secrets_credstash"
394     # generic/test_camera.py: AssertionError: 500 == 200
395     "test_fetching_without_verify_ssl"
396     "test_fetching_url_with_verify_ssl"
397     # util/test_package.py: AssertionError on package.is_installed('homeassistant>=999.999.999')
398     "test_check_package_version_does_not_match"
399   ];
401   preCheck = ''
402     export HOME="$TEMPDIR"
404     # the tests require the existance of a media dir
405     mkdir /build/media
407     # error out when component test directory is missing, otherwise hidden by xdist execution :(
408     for component in ${lib.concatStringsSep " " (map lib.escapeShellArg componentTests)}; do
409       test -d "tests/components/$component" || {
410         >2& echo "ERROR: Tests for component '$component' were enabled, but they do not exist!"
411         exit 1
412       }
413     done
414   '';
416   passthru = {
417     inherit (py.pkgs) hass-frontend;
418     tests = {
419       inherit (nixosTests) home-assistant;
420     };
421   };
423   meta = with lib; {
424     homepage = "https://home-assistant.io/";
425     description = "Open source home automation that puts local control and privacy first";
426     license = licenses.asl20;
427     maintainers = teams.home-assistant.members;
428     platforms = platforms.linux;
429   };