Reduce executor code for docker (#4438)

* Reduce executor code for docker

* Fix pylint errors and move import/export image

* Fix test and a couple other risky executor calls

* Fix dataclass and return

* Fix test case and add one for corrupt docker

* Add some coverage

* Undo changes to docker manager startup
This commit is contained in:
Mike Degatano
2023-07-18 11:39:39 -04:00
committed by GitHub
parent 1f940a04fd
commit 1f92ab42ca
34 changed files with 969 additions and 847 deletions

View File

@@ -1,19 +1,24 @@
"""Test Home Assistant core."""
from unittest.mock import MagicMock, Mock, PropertyMock, patch
from awesomeversion import AwesomeVersion
from docker.errors import DockerException, ImageNotFound, NotFound
import pytest
from supervisor.const import CpuArch
from supervisor.coresys import CoreSys
from supervisor.docker.homeassistant import DockerHomeAssistant
from supervisor.docker.interface import DockerInterface
from supervisor.docker.manager import DockerAPI
from supervisor.exceptions import (
AudioUpdateError,
CodeNotaryError,
DockerError,
HomeAssistantError,
HomeAssistantJobError,
)
from supervisor.homeassistant.core import HomeAssistantCore
from supervisor.homeassistant.module import HomeAssistant
from supervisor.updater import Updater
@@ -130,3 +135,131 @@ async def test_install_other_error(
assert "Error on Home Assistant installation. Retry in 30sec" in caplog.text
capture_exception.assert_called_once_with(err)
@pytest.mark.parametrize(
"container_exists,image_exists", [(False, True), (True, False), (True, True)]
)
async def test_start(
coresys: CoreSys, container_exists: bool, image_exists: bool, path_extern
):
"""Test starting Home Assistant."""
if image_exists:
coresys.docker.images.get.return_value.id = "123"
else:
coresys.docker.images.get.side_effect = ImageNotFound("missing")
if container_exists:
coresys.docker.containers.get.return_value.image.id = "123"
else:
coresys.docker.containers.get.side_effect = NotFound("missing")
with patch.object(
HomeAssistant,
"version",
new=PropertyMock(return_value=AwesomeVersion("2023.7.0")),
), patch.object(DockerAPI, "run") as run, patch.object(
HomeAssistantCore, "_block_till_run"
) as block_till_run:
await coresys.homeassistant.core.start()
block_till_run.assert_called_once()
run.assert_called_once()
assert (
run.call_args.args[0] == "ghcr.io/home-assistant/qemux86-64-homeassistant"
)
assert run.call_args.kwargs["tag"] == AwesomeVersion("2023.7.0")
assert run.call_args.kwargs["name"] == "homeassistant"
assert run.call_args.kwargs["hostname"] == "homeassistant"
coresys.docker.containers.get.return_value.stop.assert_not_called()
if container_exists:
coresys.docker.containers.get.return_value.remove.assert_called_once_with(
force=True
)
else:
coresys.docker.containers.get.return_value.remove.assert_not_called()
async def test_start_existing_container(coresys: CoreSys, path_extern):
"""Test starting Home Assistant when container exists and is viable."""
coresys.docker.images.get.return_value.id = "123"
coresys.docker.containers.get.return_value.image.id = "123"
coresys.docker.containers.get.return_value.status = "exited"
with patch.object(
HomeAssistant,
"version",
new=PropertyMock(return_value=AwesomeVersion("2023.7.0")),
), patch.object(HomeAssistantCore, "_block_till_run") as block_till_run:
await coresys.homeassistant.core.start()
block_till_run.assert_called_once()
coresys.docker.containers.get.return_value.start.assert_called_once()
coresys.docker.containers.get.return_value.stop.assert_not_called()
coresys.docker.containers.get.return_value.remove.assert_not_called()
coresys.docker.containers.get.return_value.run.assert_not_called()
@pytest.mark.parametrize("exists", [True, False])
async def test_stop(coresys: CoreSys, exists: bool):
"""Test stoppping Home Assistant."""
if exists:
coresys.docker.containers.get.return_value.status = "running"
else:
coresys.docker.containers.get.side_effect = NotFound("missing")
await coresys.homeassistant.core.stop()
coresys.docker.containers.get.return_value.remove.assert_not_called()
if exists:
coresys.docker.containers.get.return_value.stop.assert_called_once_with(
timeout=240
)
else:
coresys.docker.containers.get.return_value.stop.assert_not_called()
async def test_restart(coresys: CoreSys):
"""Test restarting Home Assistant."""
with patch.object(HomeAssistantCore, "_block_till_run") as block_till_run:
await coresys.homeassistant.core.restart()
block_till_run.assert_called_once()
coresys.docker.containers.get.return_value.restart.assert_called_once_with(
timeout=240
)
coresys.docker.containers.get.return_value.stop.assert_not_called()
@pytest.mark.parametrize("get_error", [NotFound("missing"), DockerException(), None])
async def test_restart_failures(coresys: CoreSys, get_error: DockerException | None):
"""Test restart fails when container missing or can't be restarted."""
coresys.docker.containers.get.return_value.restart.side_effect = DockerException()
if get_error:
coresys.docker.containers.get.side_effect = get_error
with pytest.raises(HomeAssistantError):
await coresys.homeassistant.core.restart()
@pytest.mark.parametrize(
"get_error,status",
[
(NotFound("missing"), ""),
(DockerException(), ""),
(None, "stopped"),
(None, "running"),
],
)
async def test_stats_failures(
coresys: CoreSys, get_error: DockerException | None, status: str
):
"""Test errors when getting stats."""
coresys.docker.containers.get.return_value.status = status
coresys.docker.containers.get.return_value.stats.side_effect = DockerException()
if get_error:
coresys.docker.containers.get.side_effect = get_error
with pytest.raises(HomeAssistantError):
await coresys.homeassistant.core.stats()