This commit is contained in:
Paulus Schoutsen 2023-01-02 22:06:36 -05:00 committed by GitHub
commit cc6a2f0338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 93 additions and 13 deletions

View File

@ -70,6 +70,7 @@ def api_error(
class AddonInfo:
"""Represent the current add-on info state."""
available: bool
hostname: str | None
options: dict[str, Any]
state: AddonState
@ -144,6 +145,7 @@ class AddonManager:
self._logger.debug("Add-on store info: %s", addon_store_info)
if not addon_store_info["installed"]:
return AddonInfo(
available=addon_store_info["available"],
hostname=None,
options={},
state=AddonState.NOT_INSTALLED,
@ -154,6 +156,7 @@ class AddonManager:
addon_info = await async_get_addon_info(self._hass, self.addon_slug)
addon_state = self.async_get_addon_state(addon_info)
return AddonInfo(
available=addon_info["available"],
hostname=addon_info["hostname"],
options=addon_info["options"],
state=addon_state,
@ -184,6 +187,11 @@ class AddonManager:
@api_error("Failed to install the {addon_name} add-on")
async def async_install_addon(self) -> None:
"""Install the managed add-on."""
addon_info = await self.async_get_addon_info()
if not addon_info.available:
raise AddonError(f"{self.addon_name} add-on is not available anymore")
await async_install_addon(self._hass, self.addon_slug)
@api_error("Failed to uninstall the {addon_name} add-on")
@ -196,6 +204,9 @@ class AddonManager:
"""Update the managed add-on if needed."""
addon_info = await self.async_get_addon_info()
if not addon_info.available:
raise AddonError(f"{self.addon_name} add-on is not available anymore")
if addon_info.state is AddonState.NOT_INSTALLED:
raise AddonError(f"{self.addon_name} add-on is not installed")

View File

@ -8,7 +8,7 @@ from .backports.enum import StrEnum
APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2022
MINOR_VERSION: Final = 12
PATCH_VERSION: Final = "8"
PATCH_VERSION: Final = "9"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "homeassistant"
version = "2022.12.8"
version = "2022.12.9"
license = {text = "Apache-2.0"}
description = "Open-source home automation platform running on Python 3."
readme = "README.rst"

View File

@ -32,6 +32,7 @@ def addon_not_installed_fixture(
addon_store_info: AsyncMock, addon_info: AsyncMock
) -> AsyncMock:
"""Mock add-on not installed."""
addon_store_info.return_value["available"] = True
return addon_info
@ -41,10 +42,12 @@ def mock_addon_installed(
) -> AsyncMock:
"""Mock add-on already installed but not running."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "stopped",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["hostname"] = "core-test-addon"
addon_info.return_value["state"] = "stopped"
addon_info.return_value["version"] = "1.0.0"
@ -67,6 +70,7 @@ def addon_store_info_fixture() -> Generator[AsyncMock, None, None]:
"homeassistant.components.hassio.addon_manager.async_get_addon_store_info"
) as addon_store_info:
addon_store_info.return_value = {
"available": False,
"installed": None,
"state": None,
"version": "1.0.0",
@ -81,6 +85,7 @@ def addon_info_fixture() -> Generator[AsyncMock, None, None]:
"homeassistant.components.hassio.addon_manager.async_get_addon_info",
) as addon_info:
addon_info.return_value = {
"available": False,
"hostname": None,
"options": {},
"state": None,
@ -180,6 +185,26 @@ async def test_not_installed_raises_exception(
assert str(err.value) == "Test add-on is not installed"
async def test_not_available_raises_exception(
addon_manager: AddonManager,
addon_store_info: AsyncMock,
addon_info: AsyncMock,
) -> None:
"""Test addon not available raises exception."""
addon_store_info.return_value["available"] = False
addon_info.return_value["available"] = False
with pytest.raises(AddonError) as err:
await addon_manager.async_install_addon()
assert str(err.value) == "Test add-on is not available anymore"
with pytest.raises(AddonError) as err:
await addon_manager.async_update_addon()
assert str(err.value) == "Test add-on is not available anymore"
async def test_get_addon_discovery_info(
addon_manager: AddonManager, get_addon_discovery_info: AsyncMock
) -> None:
@ -222,6 +247,7 @@ async def test_get_addon_info_not_installed(
) -> None:
"""Test get addon info when addon is not installed.."""
assert await addon_manager.async_get_addon_info() == AddonInfo(
available=True,
hostname=None,
options={},
state=AddonState.NOT_INSTALLED,
@ -243,6 +269,7 @@ async def test_get_addon_info(
"""Test get addon info when addon is installed."""
addon_installed.return_value["state"] = addon_info_state
assert await addon_manager.async_get_addon_info() == AddonInfo(
available=True,
hostname="core-test-addon",
options={},
state=addon_state,
@ -308,18 +335,29 @@ async def test_set_addon_options_error(
async def test_install_addon(
addon_manager: AddonManager, install_addon: AsyncMock
addon_manager: AddonManager,
install_addon: AsyncMock,
addon_store_info: AsyncMock,
addon_info: AsyncMock,
) -> None:
"""Test install addon."""
addon_store_info.return_value["available"] = True
addon_info.return_value["available"] = True
await addon_manager.async_install_addon()
assert install_addon.call_count == 1
async def test_install_addon_error(
addon_manager: AddonManager, install_addon: AsyncMock
addon_manager: AddonManager,
install_addon: AsyncMock,
addon_store_info: AsyncMock,
addon_info: AsyncMock,
) -> None:
"""Test install addon raises error."""
addon_store_info.return_value["available"] = True
addon_info.return_value["available"] = True
install_addon.side_effect = HassioAPIError("Boom")
with pytest.raises(AddonError) as err:
@ -341,6 +379,7 @@ async def test_schedule_install_addon(
assert addon_manager.task_in_progress() is True
assert await addon_manager.async_get_addon_info() == AddonInfo(
available=True,
hostname="core-test-addon",
options={},
state=AddonState.INSTALLING,
@ -676,6 +715,7 @@ async def test_schedule_update_addon(
assert addon_manager.task_in_progress() is True
assert await addon_manager.async_get_addon_info() == AddonInfo(
available=True,
hostname="core-test-addon",
options={},
state=AddonState.UPDATING,

View File

@ -67,6 +67,7 @@ def addon_store_info_fixture():
"homeassistant.components.hassio.addon_manager.async_get_addon_store_info"
) as addon_store_info:
addon_store_info.return_value = {
"available": True,
"installed": None,
"state": None,
"version": "1.0.0",
@ -81,6 +82,7 @@ def addon_info_fixture():
"homeassistant.components.hassio.addon_manager.async_get_addon_info",
) as addon_info:
addon_info.return_value = {
"available": True,
"hostname": None,
"options": {},
"state": None,

View File

@ -69,6 +69,7 @@ def addon_store_info_fixture():
"homeassistant.components.hassio.addon_manager.async_get_addon_store_info"
) as addon_store_info:
addon_store_info.return_value = {
"available": True,
"installed": None,
"state": None,
"version": "1.0.0",
@ -83,6 +84,7 @@ def addon_info_fixture():
"homeassistant.components.hassio.addon_manager.async_get_addon_info",
) as addon_info:
addon_info.return_value = {
"available": True,
"hostname": None,
"options": {},
"state": None,

View File

@ -67,6 +67,7 @@ def addon_store_info_fixture():
"homeassistant.components.hassio.addon_manager.async_get_addon_store_info"
) as addon_store_info:
addon_store_info.return_value = {
"available": True,
"installed": None,
"state": None,
"version": "1.0.0",
@ -81,6 +82,7 @@ def addon_info_fixture():
"homeassistant.components.hassio.addon_manager.async_get_addon_info",
) as addon_info:
addon_info.return_value = {
"available": True,
"hostname": None,
"options": {},
"state": None,

View File

@ -1,4 +1,6 @@
"""Test homekit_controller diagnostics."""
from unittest.mock import ANY
from aiohttp import ClientSession
from homeassistant.components.homekit_controller.const import KNOWN_DEVICES
@ -247,8 +249,8 @@ async def test_config_entry(hass: HomeAssistant, hass_client: ClientSession, utc
"friendly_name": "Koogeek-LS1-20833F Identify"
},
"entity_id": "button.koogeek_ls1_20833f_identify",
"last_changed": "2023-01-01T00:00:00+00:00",
"last_updated": "2023-01-01T00:00:00+00:00",
"last_changed": ANY,
"last_updated": ANY,
"state": "unknown",
},
"unit_of_measurement": None,
@ -269,8 +271,8 @@ async def test_config_entry(hass: HomeAssistant, hass_client: ClientSession, utc
"supported_features": 0,
},
"entity_id": "light.koogeek_ls1_20833f_light_strip",
"last_changed": "2023-01-01T00:00:00+00:00",
"last_updated": "2023-01-01T00:00:00+00:00",
"last_changed": ANY,
"last_updated": ANY,
"state": "off",
},
"unit_of_measurement": None,
@ -518,8 +520,8 @@ async def test_device(hass: HomeAssistant, hass_client: ClientSession, utcnow):
"friendly_name": "Koogeek-LS1-20833F " "Identify"
},
"entity_id": "button.koogeek_ls1_20833f_identify",
"last_changed": "2023-01-01T00:00:00+00:00",
"last_updated": "2023-01-01T00:00:00+00:00",
"last_changed": ANY,
"last_updated": ANY,
"state": "unknown",
},
"unit_of_measurement": None,
@ -540,8 +542,8 @@ async def test_device(hass: HomeAssistant, hass_client: ClientSession, utcnow):
"supported_features": 0,
},
"entity_id": "light.koogeek_ls1_20833f_light_strip",
"last_changed": "2023-01-01T00:00:00+00:00",
"last_updated": "2023-01-01T00:00:00+00:00",
"last_changed": ANY,
"last_updated": ANY,
"state": "off",
},
"unit_of_measurement": None,

View File

@ -77,6 +77,7 @@ def addon_store_info_fixture() -> Generator[AsyncMock, None, None]:
"homeassistant.components.hassio.addon_manager.async_get_addon_store_info"
) as addon_store_info:
addon_store_info.return_value = {
"available": False,
"installed": None,
"state": None,
"version": "1.0.0",
@ -91,6 +92,7 @@ def addon_info_fixture() -> Generator[AsyncMock, None, None]:
"homeassistant.components.hassio.addon_manager.async_get_addon_info",
) as addon_info:
addon_info.return_value = {
"available": False,
"hostname": None,
"options": {},
"state": None,
@ -105,6 +107,7 @@ def addon_not_installed_fixture(
addon_store_info: AsyncMock, addon_info: AsyncMock
) -> AsyncMock:
"""Mock add-on not installed."""
addon_store_info.return_value["available"] = True
return addon_info
@ -114,10 +117,12 @@ def addon_installed_fixture(
) -> AsyncMock:
"""Mock add-on already installed but not running."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "stopped",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["hostname"] = "core-matter-server"
addon_info.return_value["state"] = "stopped"
addon_info.return_value["version"] = "1.0.0"
@ -130,10 +135,12 @@ def addon_running_fixture(
) -> AsyncMock:
"""Mock add-on already running."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "started",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["hostname"] = "core-matter-server"
addon_info.return_value["state"] = "started"
addon_info.return_value["version"] = "1.0.0"
@ -149,10 +156,12 @@ def install_addon_fixture(
async def install_addon_side_effect(hass: HomeAssistant, slug: str) -> None:
"""Mock install add-on."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "stopped",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["state"] = "stopped"
addon_info.return_value["version"] = "1.0.0"

View File

@ -116,7 +116,7 @@ async def test_install_addon(
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.SETUP_RETRY
assert addon_store_info.call_count == 2
assert addon_store_info.call_count == 3
assert install_addon.call_count == 1
assert install_addon.call_args == call(hass, "core_matter_server")
assert start_addon.call_count == 1

View File

@ -30,6 +30,7 @@ def mock_addon_info(addon_info_side_effect):
side_effect=addon_info_side_effect,
) as addon_info:
addon_info.return_value = {
"available": False,
"hostname": None,
"options": {},
"state": None,
@ -53,6 +54,7 @@ def mock_addon_store_info(addon_store_info_side_effect):
side_effect=addon_store_info_side_effect,
) as addon_store_info:
addon_store_info.return_value = {
"available": False,
"installed": None,
"state": None,
"version": "1.0.0",
@ -64,10 +66,12 @@ def mock_addon_store_info(addon_store_info_side_effect):
def mock_addon_running(addon_store_info, addon_info):
"""Mock add-on already running."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "started",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["state"] = "started"
addon_info.return_value["version"] = "1.0.0"
return addon_info
@ -77,10 +81,12 @@ def mock_addon_running(addon_store_info, addon_info):
def mock_addon_installed(addon_store_info, addon_info):
"""Mock add-on already installed but not running."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "stopped",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["state"] = "stopped"
addon_info.return_value["version"] = "1.0.0"
return addon_info
@ -89,6 +95,7 @@ def mock_addon_installed(addon_store_info, addon_info):
@pytest.fixture(name="addon_not_installed")
def mock_addon_not_installed(addon_store_info, addon_info):
"""Mock add-on not installed."""
addon_store_info.return_value["available"] = True
return addon_info
@ -126,10 +133,12 @@ def install_addon_side_effect_fixture(addon_store_info, addon_info):
async def install_addon(hass, slug):
"""Mock install add-on."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "stopped",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["state"] = "stopped"
addon_info.return_value["version"] = "1.0.0"
@ -162,10 +171,12 @@ def start_addon_side_effect_fixture(addon_store_info, addon_info):
async def start_addon(hass, slug):
"""Mock start add-on."""
addon_store_info.return_value = {
"available": True,
"installed": "1.0.0",
"state": "started",
"version": "1.0.0",
}
addon_info.return_value["available"] = True
addon_info.return_value["state"] = "started"
return start_addon

View File

@ -536,6 +536,7 @@ async def test_abort_hassio_discovery_for_other_addon(
async def test_usb_discovery(
hass,
supervisor,
addon_not_installed,
install_addon,
addon_options,
get_addon_discovery_info,