1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-05-20 06:38:53 +01:00
Files
supervisor/tests/resolution/fixup/test_addon_execute_restart.py
T
Mike Degatano ba8c49935b Refactor internal addon references to app/apps (#6717)
* Rename addon→app in docstrings and comments

Updates all docstrings and inline comments across supervisor/ and
tests/ to use the new app/apps terminology. No runtime behaviour
is changed by this commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Rename addon→app in code (variables, args, class names, functions)

Renames all internal Python identifiers from addon/addons to app/apps:
- Variable and argument names
- Function and method names
- Class names (Addon→App, AddonManager→AppManager, DockerAddon→DockerApp,
  all exception, check, and fixup classes, etc.)
- String literals used as Python identifiers (pytest fixtures,
  parametrize param names, patch.object attribute strings,
  URL route match_info keys)

External API contracts are preserved: JSON keys, error codes,
discovery protocol fields, TypedDict/attr.s field names.
Import module paths (supervisor/addons/) are also unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix partial backup/restore API to remap addons key to apps

The external API accepts `addons` as the request body key (since
ATTR_APPS = "addons"), but do_backup_partial and do_restore_partial
now take an `apps` parameter after the rename. The **body expansion
in both endpoints would pass `addons=...` causing a TypeError.

Remap the key before expansion in both backup_partial and
restore_partial:

    if ATTR_APPS in body:
        body["apps"] = body.pop(ATTR_APPS)

Also adds test_restore_partial_with_addons_key to verify the restore
path correctly receives apps= when addons is passed in the request
body. This path had no existing test coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix merge error

* Adjust AppLoggerAdapter to use app_name

Co-authored-by: Stefan Agner <stefan@agner.ch>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Stefan Agner <stefan@agner.ch>
2026-04-14 16:47:20 +02:00

121 lines
4.0 KiB
Python

"""Test fixup app execute restart."""
from unittest.mock import patch
import pytest
from supervisor.addons.addon import App
from supervisor.const import AppState
from supervisor.coresys import CoreSys
from supervisor.docker.addon import DockerApp
from supervisor.docker.interface import DockerInterface
from supervisor.exceptions import DockerError
from supervisor.resolution.const import ContextType, IssueType, SuggestionType
from supervisor.resolution.data import Issue, Suggestion
from supervisor.resolution.fixups.addon_execute_restart import FixupAppExecuteRestart
from tests.const import TEST_ADDON_SLUG
DEVICE_ACCESS_MISSING_ISSUE = Issue(
IssueType.DEVICE_ACCESS_MISSING,
ContextType.ADDON,
reference=TEST_ADDON_SLUG,
)
EXECUTE_RESTART_SUGGESTION = Suggestion(
SuggestionType.EXECUTE_RESTART, ContextType.ADDON, reference="local_ssh"
)
@pytest.mark.usefixtures("path_extern")
async def test_fixup(coresys: CoreSys, install_app_ssh: App):
"""Test fixup restarts app."""
install_app_ssh.state = AppState.STARTED
app_execute_restart = FixupAppExecuteRestart(coresys)
assert app_execute_restart.auto is False
async def mock_stop(*args, **kwargs):
install_app_ssh.state = AppState.STOPPED
coresys.resolution.add_issue(
DEVICE_ACCESS_MISSING_ISSUE,
suggestions=[SuggestionType.EXECUTE_RESTART],
)
with (
patch.object(DockerInterface, "stop") as stop,
patch.object(DockerApp, "run") as run,
patch.object(App, "_wait_for_startup"),
patch.object(App, "write_options"),
):
await app_execute_restart()
stop.assert_called_once()
run.assert_called_once()
assert not coresys.resolution.issues
assert not coresys.resolution.suggestions
@pytest.mark.usefixtures("path_extern")
async def test_fixup_stop_error(
coresys: CoreSys, install_app_ssh: App, caplog: pytest.LogCaptureFixture
):
"""Test fixup fails on stop app failure."""
install_app_ssh.state = AppState.STARTED
app_execute_start = FixupAppExecuteRestart(coresys)
coresys.resolution.add_issue(
DEVICE_ACCESS_MISSING_ISSUE,
suggestions=[SuggestionType.EXECUTE_RESTART],
)
with (
patch.object(DockerInterface, "stop", side_effect=DockerError),
patch.object(DockerApp, "run") as run,
):
await app_execute_start()
run.assert_not_called()
assert DEVICE_ACCESS_MISSING_ISSUE in coresys.resolution.issues
assert EXECUTE_RESTART_SUGGESTION in coresys.resolution.suggestions
assert "Could not stop local_ssh" in caplog.text
@pytest.mark.usefixtures("path_extern")
async def test_fixup_start_error(
coresys: CoreSys, install_app_ssh: App, caplog: pytest.LogCaptureFixture
):
"""Test fixup logs a start app failure."""
install_app_ssh.state = AppState.STARTED
app_execute_start = FixupAppExecuteRestart(coresys)
coresys.resolution.add_issue(
DEVICE_ACCESS_MISSING_ISSUE,
suggestions=[SuggestionType.EXECUTE_RESTART],
)
with (
patch.object(DockerInterface, "stop") as stop,
patch.object(DockerApp, "run", side_effect=DockerError),
patch.object(App, "write_options"),
):
await app_execute_start()
stop.assert_called_once()
assert DEVICE_ACCESS_MISSING_ISSUE not in coresys.resolution.issues
assert EXECUTE_RESTART_SUGGESTION not in coresys.resolution.suggestions
assert "Could not restart local_ssh" in caplog.text
async def test_fixup_no_app(coresys: CoreSys, caplog: pytest.LogCaptureFixture):
"""Test fixup dismisses if app is missing."""
app_execute_start = FixupAppExecuteRestart(coresys)
coresys.resolution.add_issue(
DEVICE_ACCESS_MISSING_ISSUE,
suggestions=[SuggestionType.EXECUTE_RESTART],
)
with patch.object(DockerApp, "stop") as stop:
await app_execute_start()
stop.assert_not_called()
assert not coresys.resolution.issues
assert not coresys.resolution.suggestions
assert "Cannot restart app local_ssh as it does not exist" in caplog.text