mirror of
https://github.com/home-assistant/operating-system.git
synced 2025-12-11 11:03:19 -06:00
When there's a problem with connectivity, it may result in obscure errors later in the testing. Add checks testing three scenarions: * connectivity in host - both using curl and nmcli * connectivity in Supervisor container (uses docker0 as default via) * connectivity in CLI container (uses hassio as default via) Also make sure that Supervisor upgrade isn't attempted when the version information is missing.
210 lines
8.6 KiB
Python
210 lines
8.6 KiB
Python
import logging
|
|
from time import sleep
|
|
|
|
import pytest
|
|
from labgrid.driver import ExecutionError
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def stash() -> dict:
|
|
"""Simple stash for sharing data between tests in this module."""
|
|
stash = {}
|
|
return stash
|
|
|
|
|
|
@pytest.mark.dependency()
|
|
@pytest.mark.timeout(120)
|
|
def test_start_supervisor(shell, shell_json):
|
|
def check_container_running(container_name):
|
|
out = shell.run_check(f"docker container inspect -f '{{{{.State.Status}}}}' {container_name} || true")
|
|
return "running" in out
|
|
|
|
while True:
|
|
if check_container_running("homeassistant") and check_container_running("hassio_supervisor"):
|
|
break
|
|
|
|
sleep(1)
|
|
|
|
supervisor_ip = "\n".join(
|
|
shell.run_check("docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor")
|
|
)
|
|
|
|
while True:
|
|
try:
|
|
if shell_json(f"curl -sSL http://{supervisor_ip}/supervisor/ping").get("result") == "ok":
|
|
break
|
|
except ExecutionError:
|
|
pass # avoid failure when the container is restarting
|
|
|
|
sleep(1)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_start_supervisor"])
|
|
def test_check_supervisor(shell_json):
|
|
# check supervisor info
|
|
supervisor_info = shell_json("ha supervisor info --no-progress --raw-json")
|
|
assert supervisor_info.get("result") == "ok", "supervisor info failed"
|
|
logger.info("Supervisor info: %s", supervisor_info)
|
|
# check network info
|
|
network_info = shell_json("ha network info --no-progress --raw-json")
|
|
assert network_info.get("result") == "ok", "network info failed"
|
|
logger.info("Network info: %s", network_info)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_check_supervisor"])
|
|
@pytest.mark.timeout(120)
|
|
def test_update_supervisor(shell_json):
|
|
supervisor_info = shell_json("ha supervisor info --no-progress --raw-json")
|
|
supervisor_version = supervisor_info.get("data").get("version")
|
|
supervisor_version_latest = supervisor_info.get("data").get("version_latest")
|
|
assert supervisor_version_latest, "Missing latest supervisor version info"
|
|
if supervisor_version == supervisor_version_latest:
|
|
logger.info("Supervisor is already up to date")
|
|
pytest.skip("Supervisor is already up to date")
|
|
else:
|
|
result = shell_json("ha supervisor update --no-progress --raw-json")
|
|
if result.get("result") == "error" and "Another job is running" in result.get("message"):
|
|
pass
|
|
else:
|
|
assert result.get("result") == "ok", f"Supervisor update failed: {result}"
|
|
|
|
while True:
|
|
try:
|
|
supervisor_info = shell_json("ha supervisor info --no-progress --raw-json")
|
|
data = supervisor_info.get("data")
|
|
if data and data.get("version") == data.get("version_latest"):
|
|
logger.info(
|
|
"Supervisor updated from %s to %s: %s",
|
|
supervisor_version,
|
|
data.get("version"),
|
|
supervisor_info,
|
|
)
|
|
break
|
|
except ExecutionError:
|
|
pass # avoid failure when the container is restarting
|
|
|
|
sleep(1)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_check_supervisor"])
|
|
def test_supervisor_is_updated(shell_json):
|
|
supervisor_info = shell_json("ha supervisor info --no-progress --raw-json")
|
|
data = supervisor_info.get("data")
|
|
assert data and data.get("version") == data.get("version_latest")
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_supervisor_is_updated"])
|
|
def test_addon_install(shell_json):
|
|
# install Core SSH add-on
|
|
assert (
|
|
shell_json("ha addons install core_ssh --no-progress --raw-json").get("result") == "ok"
|
|
), "Core SSH add-on install failed"
|
|
# check Core SSH add-on is installed
|
|
assert (
|
|
shell_json("ha addons info core_ssh --no-progress --raw-json").get("data", {}).get("version") is not None
|
|
), "Core SSH add-on not installed"
|
|
# start Core SSH add-on
|
|
assert (
|
|
shell_json("ha addons start core_ssh --no-progress --raw-json").get("result") == "ok"
|
|
), "Core SSH add-on start failed"
|
|
# check Core SSH add-on is running
|
|
ssh_info = shell_json("ha addons info core_ssh --no-progress --raw-json")
|
|
assert ssh_info.get("data", {}).get("state") == "started", "Core SSH add-on not running"
|
|
logger.info("Core SSH add-on info: %s", ssh_info)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_supervisor_is_updated"])
|
|
def test_code_sign(shell_json):
|
|
# enable Content-Trust
|
|
assert (
|
|
shell_json("ha security options --content-trust=true --no-progress --raw-json").get("result") == "ok"
|
|
), "Content-Trust enable failed"
|
|
# run Supervisor health check
|
|
health_check = shell_json("ha resolution healthcheck --no-progress --raw-json")
|
|
assert health_check.get("result") == "ok", "Supervisor health check failed"
|
|
logger.info("Supervisor health check result: %s", health_check)
|
|
# get resolution center info
|
|
resolution_info = shell_json("ha resolution info --no-progress --raw-json")
|
|
logger.info("Resolution center info: %s", resolution_info)
|
|
# check supervisor is healthy
|
|
unhealthy = resolution_info.get("data").get("unhealthy")
|
|
assert len(unhealthy) == 0, "Supervisor is unhealthy"
|
|
# check for unsupported entries
|
|
unsupported = resolution_info.get("data").get("unsupported")
|
|
assert len(unsupported) == 0, "Unsupported entries found"
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_supervisor_is_updated"])
|
|
def test_create_backup(shell_json, stash):
|
|
result = shell_json("ha backups new --no-progress --raw-json")
|
|
assert result.get("result") == "ok", f"Backup creation failed: {result}"
|
|
slug = result.get("data", {}).get("slug")
|
|
assert slug is not None
|
|
stash.update(slug=slug)
|
|
logger.info("Backup creation result: %s", result)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_addon_install"])
|
|
def test_addon_uninstall(shell_json):
|
|
result = shell_json("ha addons uninstall core_ssh --no-progress --raw-json")
|
|
assert result.get("result") == "ok", f"Core SSH add-on uninstall failed: {result}"
|
|
logger.info("Core SSH add-on uninstall result: %s", result)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_supervisor_is_updated"])
|
|
@pytest.mark.timeout(120)
|
|
def test_restart_supervisor(shell, shell_json):
|
|
result = shell_json("ha supervisor restart --no-progress --raw-json")
|
|
assert result.get("result") == "ok", f"Supervisor restart failed: {result}"
|
|
|
|
supervisor_ip = "\n".join(
|
|
shell.run_check("docker inspect --format='{{.NetworkSettings.IPAddress}}' hassio_supervisor")
|
|
)
|
|
|
|
while True:
|
|
try:
|
|
if shell_json(f"curl -sSL http://{supervisor_ip}/supervisor/ping").get("result") == "ok":
|
|
if shell_json("ha os info --no-progress --raw-json").get("result") == "ok":
|
|
break
|
|
except ExecutionError:
|
|
pass # avoid failure when the container is restarting
|
|
|
|
sleep(1)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_create_backup"])
|
|
def test_restore_backup(shell_json, stash):
|
|
result = shell_json(f"ha backups restore {stash.get('slug')} --addons core_ssh --no-progress --raw-json")
|
|
assert result.get("result") == "ok", f"Backup restore failed: {result}"
|
|
logger.info("Backup restore result: %s", result)
|
|
|
|
addon_info = shell_json("ha addons info core_ssh --no-progress --raw-json")
|
|
assert addon_info.get("data", {}).get("version") is not None, "Core SSH add-on not installed"
|
|
assert addon_info.get("data", {}).get("state") == "started", "Core SSH add-on not running"
|
|
logger.info("Core SSH add-on info: %s", addon_info)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_create_backup"])
|
|
def test_restore_ssl_directory(shell_json, stash):
|
|
result = shell_json(f"ha backups restore {stash.get('slug')} --folders ssl --no-progress --raw-json")
|
|
assert result.get("result") == "ok", f"Backup restore failed: {result}"
|
|
logger.info("Backup restore result: %s", result)
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_start_supervisor"])
|
|
def test_no_apparmor_denies(shell):
|
|
"""Check there are no AppArmor denies in the logs raised during Supervisor tests."""
|
|
output = shell.run_check("journalctl -t audit | grep DENIED || true")
|
|
assert not output, f"AppArmor denies found: {output}"
|
|
|
|
|
|
@pytest.mark.dependency(depends=["test_start_supervisor"])
|
|
def test_kernel_not_tainted(shell):
|
|
"""Check if the kernel is not tainted - do it at the end of the
|
|
test suite to increase the chance of catching issues."""
|
|
output = shell.run_check("cat /proc/sys/kernel/tainted")
|
|
assert "\n".join(output) == "0", f"Kernel tainted: {output}"
|