mirror of
https://github.com/home-assistant/supervisor.git
synced 2026-07-06 13:25:05 +01:00
355396aeab
* Migrate config file and directory paths from addons to apps
- Rename addons.json -> apps.json (FILE_HASSIO_APPS constant)
- Rename addons/{core,data,local,git} -> apps/{core,data,local,git}
- Rename addon_configs -> app_configs
Backwards compatibility: on startup, Supervisor checks for legacy
paths and renames them if the new paths don't already exist.
- addons.json migration runs in AppManager.load_config (executor)
- Directory migrations run in bootstrap before initialize_system (executor)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Rename SCHEMA_ADDON(S)_* constants to SCHEMA_APP(S)_* in apps/validate.py
Update all references in supervisor and tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix remaining test references to legacy addons/* paths
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Opportunistic remove of addons dir since it should be empty post migration
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
149 lines
5.1 KiB
Python
149 lines
5.1 KiB
Python
"""Test evaluation base."""
|
|
|
|
# pylint: disable=import-error,protected-access
|
|
import errno
|
|
from pathlib import Path
|
|
from unittest.mock import PropertyMock, patch
|
|
|
|
import pytest
|
|
|
|
from supervisor.config import CoreConfig
|
|
from supervisor.coresys import CoreSys
|
|
from supervisor.exceptions import StoreGitCloneError
|
|
from supervisor.resolution.const import (
|
|
ContextType,
|
|
IssueType,
|
|
SuggestionType,
|
|
UnhealthyReason,
|
|
)
|
|
from supervisor.resolution.data import Issue, Suggestion
|
|
from supervisor.resolution.fixups.store_execute_reset import FixupStoreExecuteReset
|
|
from supervisor.store.git import GitRepo
|
|
from supervisor.store.repository import Repository
|
|
|
|
|
|
@pytest.fixture(name="mock_addons_git", autouse=True)
|
|
async def fixture_mock_apps_git(tmp_supervisor_data: Path) -> None:
|
|
"""Mock apps git path."""
|
|
with patch.object(
|
|
CoreConfig,
|
|
"path_apps_git",
|
|
new=PropertyMock(return_value=tmp_supervisor_data / "apps" / "git"),
|
|
):
|
|
yield
|
|
|
|
|
|
def add_store_reset_suggestion(coresys: CoreSys) -> None:
|
|
"""Add suggestion for tests."""
|
|
coresys.resolution.add_suggestion(
|
|
Suggestion(
|
|
SuggestionType.EXECUTE_RESET, ContextType.STORE, reference="94cfad5a"
|
|
)
|
|
)
|
|
coresys.resolution.add_issue(
|
|
Issue(IssueType.CORRUPT_REPOSITORY, ContextType.STORE, reference="94cfad5a")
|
|
)
|
|
|
|
|
|
@pytest.mark.usefixtures("supervisor_internet")
|
|
async def test_fixup(coresys: CoreSys):
|
|
"""Test fixup."""
|
|
store_execute_reset = FixupStoreExecuteReset(coresys)
|
|
test_repo = coresys.config.path_apps_git / "94cfad5a"
|
|
|
|
assert store_execute_reset.auto
|
|
|
|
add_store_reset_suggestion(coresys)
|
|
test_repo.mkdir(parents=True)
|
|
good_marker = test_repo / ".git"
|
|
(corrupt_marker := (test_repo / "corrupt")).touch()
|
|
assert test_repo.exists()
|
|
assert not good_marker.exists()
|
|
assert corrupt_marker.exists()
|
|
|
|
async def mock_clone(obj: GitRepo, path: Path | None = None):
|
|
"""Mock of clone method."""
|
|
path = path or obj.path
|
|
await coresys.run_in_executor((path / ".git").mkdir)
|
|
|
|
coresys.store.repositories["94cfad5a"] = Repository.create(
|
|
coresys, "https://github.com/home-assistant/addons-example"
|
|
)
|
|
with (
|
|
patch.object(GitRepo, "load"),
|
|
patch.object(GitRepo, "_clone", new=mock_clone),
|
|
patch("shutil.disk_usage", return_value=(42, 42, 2 * (1024.0**3))),
|
|
):
|
|
await store_execute_reset()
|
|
|
|
assert test_repo.exists()
|
|
assert good_marker.exists()
|
|
assert not corrupt_marker.exists()
|
|
assert len(coresys.resolution.suggestions) == 0
|
|
assert len(coresys.resolution.issues) == 0
|
|
assert len(list(coresys.config.path_tmp.iterdir())) == 0
|
|
|
|
|
|
@pytest.mark.usefixtures("supervisor_internet")
|
|
async def test_fixup_clone_fail(coresys: CoreSys):
|
|
"""Test fixup does not delete cache when clone fails."""
|
|
store_execute_reset = FixupStoreExecuteReset(coresys)
|
|
test_repo = coresys.config.path_apps_git / "94cfad5a"
|
|
|
|
add_store_reset_suggestion(coresys)
|
|
test_repo.mkdir(parents=True)
|
|
(corrupt_marker := (test_repo / "corrupt")).touch()
|
|
assert test_repo.exists()
|
|
assert corrupt_marker.exists()
|
|
|
|
coresys.store.repositories["94cfad5a"] = Repository.create(
|
|
coresys, "https://github.com/home-assistant/addons-example"
|
|
)
|
|
with (
|
|
patch.object(GitRepo, "load"),
|
|
patch.object(GitRepo, "_clone", side_effect=StoreGitCloneError),
|
|
patch("shutil.disk_usage", return_value=(42, 42, 2 * (1024.0**3))),
|
|
):
|
|
await store_execute_reset()
|
|
|
|
assert test_repo.exists()
|
|
assert corrupt_marker.exists()
|
|
assert len(coresys.resolution.suggestions) == 1
|
|
assert len(coresys.resolution.issues) == 1
|
|
assert len(list(coresys.config.path_tmp.iterdir())) == 0
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("error_num", "unhealthy"), [(errno.EBUSY, False), (errno.EBADMSG, True)]
|
|
)
|
|
@pytest.mark.usefixtures("supervisor_internet")
|
|
async def test_fixup_move_fail(coresys: CoreSys, error_num: int, unhealthy: bool):
|
|
"""Test fixup cleans up clone on move fail.
|
|
|
|
This scenario shouldn't really happen unless something is pretty wrong with the system.
|
|
It will leave the user in a bind without the git cache but at least we try to clean up tmp.
|
|
"""
|
|
store_execute_reset = FixupStoreExecuteReset(coresys)
|
|
test_repo = coresys.config.path_apps_git / "94cfad5a"
|
|
|
|
add_store_reset_suggestion(coresys)
|
|
test_repo.mkdir(parents=True)
|
|
coresys.store.repositories["94cfad5a"] = Repository.create(
|
|
coresys, "https://github.com/home-assistant/addons-example"
|
|
)
|
|
with (
|
|
patch.object(GitRepo, "load"),
|
|
patch.object(GitRepo, "_clone"),
|
|
patch("supervisor.store.git.Path.rename", side_effect=(err := OSError())),
|
|
patch("shutil.disk_usage", return_value=(42, 42, 2 * (1024.0**3))),
|
|
):
|
|
err.errno = error_num
|
|
await store_execute_reset()
|
|
|
|
assert len(coresys.resolution.suggestions) == 1
|
|
assert len(coresys.resolution.issues) == 1
|
|
assert len(list(coresys.config.path_tmp.iterdir())) == 0
|
|
assert (
|
|
UnhealthyReason.OSERROR_BAD_MESSAGE in coresys.resolution.unhealthy
|
|
) is unhealthy
|