nixpkgs-suyu/nixos/tests/home-assistant.nix
Martin Weinelt d26a6e377d
nixos/tests/home-assistant: stop printing log
With multiple specialization changes this isn't very helpful anymore,
but no biggie since we check the log for errors anyway and the log is
not too verbose anyway.
2022-06-22 17:02:48 +02:00

183 lines
6.4 KiB
Nix

import ./make-test-python.nix ({ pkgs, lib, ... }:
let
configDir = "/var/lib/foobar";
in {
name = "home-assistant";
meta.maintainers = lib.teams.home-assistant.members;
nodes.hass = { pkgs, ... }: {
environment.systemPackages = with pkgs; [ mosquitto ];
services.postgresql = {
enable = true;
ensureDatabases = [ "hass" ];
ensureUsers = [{
name = "hass";
ensurePermissions = {
"DATABASE hass" = "ALL PRIVILEGES";
};
}];
};
services.home-assistant = {
enable = true;
inherit configDir;
# tests loading components by overriding the package
package = (pkgs.home-assistant.override {
extraPackages = ps: with ps; [
colorama
];
extraComponents = [ "zha" ];
}).overrideAttrs (oldAttrs: {
doInstallCheck = false;
});
# tests loading components from the module
extraComponents = [
"wake_on_lan"
];
# test extra package passing from the module
extraPackages = python3Packages: with python3Packages; [
psycopg2
];
config = {
homeassistant = {
name = "Home";
time_zone = "UTC";
latitude = "0.0";
longitude = "0.0";
elevation = 0;
};
# configure the recorder component to use the postgresql db
recorder.db_url = "postgresql://@/hass";
# we can't load default_config, because the updater requires
# network access and would cause an error, so load frontend
# here explicitly.
# https://www.home-assistant.io/integrations/frontend/
frontend = {};
# set up a wake-on-lan switch to test capset capability required
# for the ping suid wrapper
# https://www.home-assistant.io/integrations/wake_on_lan/
switch = [ {
platform = "wake_on_lan";
mac = "00:11:22:33:44:55";
host = "127.0.0.1";
} ];
# test component-based capability assignment (CAP_NET_BIND_SERVICE)
# https://www.home-assistant.io/integrations/emulated_hue/
emulated_hue = {
host_ip = "127.0.0.1";
listen_port = 80;
};
# https://www.home-assistant.io/integrations/logger/
logger = {
default = "info";
};
};
# configure the sample lovelace dashboard
lovelaceConfig = {
title = "My Awesome Home";
views = [{
title = "Example";
cards = [{
type = "markdown";
title = "Lovelace";
content = "Welcome to your **Lovelace UI**.";
}];
}];
};
lovelaceConfigWritable = true;
};
# Cause a configuration change inside `configuration.yml` and verify that the process is being reloaded.
specialisation.differentName = {
inheritParentConfig = true;
configuration.services.home-assistant.config.homeassistant.name = lib.mkForce "Test Home";
};
# Cause a configuration change that requires a service restart as we added a new runtime dependency
specialisation.newFeature = {
inheritParentConfig = true;
configuration.services.home-assistant.config.device_tracker = [
{ platform = "bluetooth_tracker"; }
];
};
};
testScript = { nodes, ... }: let
system = nodes.hass.config.system.build.toplevel;
in
''
import re
start_all()
# Parse the package path out of the systemd unit, as we cannot
# access the final package, that is overriden inside the module,
# by any other means.
pattern = re.compile(r"path=(?P<path>[\/a-z0-9-.]+)\/bin\/hass")
response = hass.execute("systemctl show -p ExecStart home-assistant.service")[1]
match = pattern.search(response)
assert match
package = match.group('path')
hass.wait_for_unit("home-assistant.service")
with subtest("Check that YAML configuration file is in place"):
hass.succeed("test -L ${configDir}/configuration.yaml")
with subtest("Check the lovelace config is copied because lovelaceConfigWritable = true"):
hass.succeed("test -f ${configDir}/ui-lovelace.yaml")
with subtest("Check extraComponents and extraPackages are considered from the package"):
hass.succeed(f"grep -q 'colorama' {package}/extra_packages")
hass.succeed(f"grep -q 'zha' {package}/extra_components")
with subtest("Check extraComponents and extraPackages are considered from the module"):
hass.succeed(f"grep -q 'psycopg2' {package}/extra_packages")
hass.succeed(f"grep -q 'wake_on_lan' {package}/extra_components")
with subtest("Check that Home Assistant's web interface and API can be reached"):
hass.wait_until_succeeds("journalctl -u home-assistant.service | grep -q 'Home Assistant initialized in'")
hass.wait_for_open_port(8123)
hass.succeed("curl --fail http://localhost:8123/lovelace")
with subtest("Check that capabilities are passed for emulated_hue to bind to port 80"):
hass.wait_for_open_port(80)
hass.succeed("curl --fail http://localhost:80/description.xml")
with subtest("Check extra components are considered in systemd unit hardening"):
hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB")
with subtest("Check service reloads when configuration changes"):
# store the old pid of the process
pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
hass.succeed("${system}/specialisation/differentName/bin/switch-to-configuration test")
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid == new_pid, "The PID of the process should not change between process reloads"
with subtest("check service restarts when package changes"):
pid = new_pid
hass.succeed("${system}/specialisation/newFeature/bin/switch-to-configuration test")
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid != new_pid, "The PID of the process shoudl change when the HA binary changes"
with subtest("Check that no errors were logged"):
output_log = hass.succeed("cat ${configDir}/home-assistant.log")
assert "ERROR" not in output_log
with subtest("Check systemd unit hardening"):
hass.log(hass.succeed("systemctl cat home-assistant.service"))
hass.log(hass.succeed("systemd-analyze security home-assistant.service"))
'';
})