"""Test the addon manager.""" from __future__ import annotations import asyncio from typing import Any from unittest.mock import AsyncMock, call import pytest from homeassistant.components.hassio.addon_manager import ( AddonError, AddonInfo, AddonManager, AddonState, ) from homeassistant.components.hassio.handler import HassioAPIError from homeassistant.core import HomeAssistant async def test_not_installed_raises_exception( addon_manager: AddonManager, addon_not_installed: dict[str, Any], ) -> None: """Test addon not installed raises exception.""" addon_config = {"test_key": "test"} with pytest.raises(AddonError) as err: await addon_manager.async_configure_addon(addon_config) assert str(err.value) == "Test add-on is not installed" with pytest.raises(AddonError) as err: await addon_manager.async_update_addon() 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" with pytest.raises(AddonError) as err: await addon_manager.async_update_addon() assert str(err.value) == "Test add-on is not available" async def test_get_addon_discovery_info( addon_manager: AddonManager, get_addon_discovery_info: AsyncMock ) -> None: """Test get addon discovery info.""" get_addon_discovery_info.return_value = {"config": {"test_key": "test"}} assert await addon_manager.async_get_addon_discovery_info() == {"test_key": "test"} assert get_addon_discovery_info.call_count == 1 async def test_missing_addon_discovery_info( addon_manager: AddonManager, get_addon_discovery_info: AsyncMock ) -> None: """Test missing addon discovery info.""" get_addon_discovery_info.return_value = None with pytest.raises(AddonError): await addon_manager.async_get_addon_discovery_info() assert get_addon_discovery_info.call_count == 1 async def test_get_addon_discovery_info_error( addon_manager: AddonManager, get_addon_discovery_info: AsyncMock ) -> None: """Test get addon discovery info raises error.""" get_addon_discovery_info.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: assert await addon_manager.async_get_addon_discovery_info() assert str(err.value) == "Failed to get the Test add-on discovery info: Boom" assert get_addon_discovery_info.call_count == 1 async def test_get_addon_info_not_installed( addon_manager: AddonManager, addon_not_installed: AsyncMock ) -> 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, update_available=False, version=None, ) @pytest.mark.parametrize( ("addon_info_state", "addon_state"), [("started", AddonState.RUNNING), ("stopped", AddonState.NOT_RUNNING)], ) async def test_get_addon_info( addon_manager: AddonManager, addon_installed: AsyncMock, addon_info_state: str, addon_state: AddonState, ) -> None: """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, update_available=False, version="1.0.0", ) @pytest.mark.parametrize( ( "addon_info_error", "addon_info_calls", "addon_store_info_error", "addon_store_info_calls", ), [(HassioAPIError("Boom"), 1, None, 1), (None, 0, HassioAPIError("Boom"), 1)], ) async def test_get_addon_info_error( addon_manager: AddonManager, addon_info: AsyncMock, addon_store_info: AsyncMock, addon_installed: AsyncMock, addon_info_error: Exception | None, addon_info_calls: int, addon_store_info_error: Exception | None, addon_store_info_calls: int, ) -> None: """Test get addon info raises error.""" addon_info.side_effect = addon_info_error addon_store_info.side_effect = addon_store_info_error with pytest.raises(AddonError) as err: await addon_manager.async_get_addon_info() assert str(err.value) == "Failed to get the Test add-on info: Boom" assert addon_info.call_count == addon_info_calls assert addon_store_info.call_count == addon_store_info_calls async def test_set_addon_options( hass: HomeAssistant, addon_manager: AddonManager, set_addon_options: AsyncMock ) -> None: """Test set addon options.""" await addon_manager.async_set_addon_options({"test_key": "test"}) assert set_addon_options.call_count == 1 assert set_addon_options.call_args == call( hass, "test_addon", {"options": {"test_key": "test"}} ) async def test_set_addon_options_error( hass: HomeAssistant, addon_manager: AddonManager, set_addon_options: AsyncMock ) -> None: """Test set addon options raises error.""" set_addon_options.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_set_addon_options({"test_key": "test"}) assert str(err.value) == "Failed to set the Test add-on options: Boom" assert set_addon_options.call_count == 1 assert set_addon_options.call_args == call( hass, "test_addon", {"options": {"test_key": "test"}} ) async def test_install_addon( 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_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: await addon_manager.async_install_addon() assert str(err.value) == "Failed to install the Test add-on: Boom" assert install_addon.call_count == 1 async def test_schedule_install_addon( addon_manager: AddonManager, addon_installed: AsyncMock, install_addon: AsyncMock, ) -> None: """Test schedule install addon.""" install_task = addon_manager.async_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, update_available=False, version="1.0.0", ) # Make sure that actually only one install task is running. install_task_two = addon_manager.async_schedule_install_addon() await asyncio.gather(install_task, install_task_two) assert addon_manager.task_in_progress() is False assert install_addon.call_count == 1 install_addon.reset_mock() # Test that another call can be made after the install is done. await addon_manager.async_schedule_install_addon() assert install_addon.call_count == 1 async def test_schedule_install_addon_error( addon_manager: AddonManager, addon_installed: AsyncMock, install_addon: AsyncMock, ) -> None: """Test schedule install addon raises error.""" install_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_schedule_install_addon() assert str(err.value) == "Failed to install the Test add-on: Boom" assert install_addon.call_count == 1 async def test_schedule_install_addon_logs_error( addon_manager: AddonManager, addon_installed: AsyncMock, install_addon: AsyncMock, caplog: pytest.LogCaptureFixture, ) -> None: """Test schedule install addon logs error.""" install_addon.side_effect = HassioAPIError("Boom") await addon_manager.async_schedule_install_addon(catch_error=True) assert "Failed to install the Test add-on: Boom" in caplog.text assert install_addon.call_count == 1 async def test_uninstall_addon( addon_manager: AddonManager, uninstall_addon: AsyncMock ) -> None: """Test uninstall addon.""" await addon_manager.async_uninstall_addon() assert uninstall_addon.call_count == 1 async def test_uninstall_addon_error( addon_manager: AddonManager, uninstall_addon: AsyncMock ) -> None: """Test uninstall addon raises error.""" uninstall_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_uninstall_addon() assert str(err.value) == "Failed to uninstall the Test add-on: Boom" assert uninstall_addon.call_count == 1 async def test_start_addon(addon_manager: AddonManager, start_addon: AsyncMock) -> None: """Test start addon.""" await addon_manager.async_start_addon() assert start_addon.call_count == 1 async def test_start_addon_error( addon_manager: AddonManager, start_addon: AsyncMock ) -> None: """Test start addon raises error.""" start_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_start_addon() assert str(err.value) == "Failed to start the Test add-on: Boom" assert start_addon.call_count == 1 async def test_schedule_start_addon( addon_manager: AddonManager, addon_installed: AsyncMock, start_addon: AsyncMock, ) -> None: """Test schedule start addon.""" start_task = addon_manager.async_schedule_start_addon() assert addon_manager.task_in_progress() is True # Make sure that actually only one start task is running. start_task_two = addon_manager.async_schedule_start_addon() await asyncio.gather(start_task, start_task_two) assert addon_manager.task_in_progress() is False assert start_addon.call_count == 1 start_addon.reset_mock() # Test that another call can be made after the start is done. await addon_manager.async_schedule_start_addon() assert start_addon.call_count == 1 async def test_schedule_start_addon_error( addon_manager: AddonManager, addon_installed: AsyncMock, start_addon: AsyncMock, ) -> None: """Test schedule start addon raises error.""" start_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_schedule_start_addon() assert str(err.value) == "Failed to start the Test add-on: Boom" assert start_addon.call_count == 1 async def test_schedule_start_addon_logs_error( addon_manager: AddonManager, addon_installed: AsyncMock, start_addon: AsyncMock, caplog: pytest.LogCaptureFixture, ) -> None: """Test schedule start addon logs error.""" start_addon.side_effect = HassioAPIError("Boom") await addon_manager.async_schedule_start_addon(catch_error=True) assert "Failed to start the Test add-on: Boom" in caplog.text assert start_addon.call_count == 1 async def test_restart_addon( addon_manager: AddonManager, restart_addon: AsyncMock ) -> None: """Test restart addon.""" await addon_manager.async_restart_addon() assert restart_addon.call_count == 1 async def test_restart_addon_error( addon_manager: AddonManager, restart_addon: AsyncMock ) -> None: """Test restart addon raises error.""" restart_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_restart_addon() assert str(err.value) == "Failed to restart the Test add-on: Boom" assert restart_addon.call_count == 1 async def test_schedule_restart_addon( addon_manager: AddonManager, addon_installed: AsyncMock, restart_addon: AsyncMock, ) -> None: """Test schedule restart addon.""" restart_task = addon_manager.async_schedule_restart_addon() assert addon_manager.task_in_progress() is True # Make sure that actually only one start task is running. restart_task_two = addon_manager.async_schedule_restart_addon() await asyncio.gather(restart_task, restart_task_two) assert addon_manager.task_in_progress() is False assert restart_addon.call_count == 1 restart_addon.reset_mock() # Test that another call can be made after the restart is done. await addon_manager.async_schedule_restart_addon() assert restart_addon.call_count == 1 async def test_schedule_restart_addon_error( addon_manager: AddonManager, addon_installed: AsyncMock, restart_addon: AsyncMock, ) -> None: """Test schedule restart addon raises error.""" restart_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_schedule_restart_addon() assert str(err.value) == "Failed to restart the Test add-on: Boom" assert restart_addon.call_count == 1 async def test_schedule_restart_addon_logs_error( addon_manager: AddonManager, addon_installed: AsyncMock, restart_addon: AsyncMock, caplog: pytest.LogCaptureFixture, ) -> None: """Test schedule restart addon logs error.""" restart_addon.side_effect = HassioAPIError("Boom") await addon_manager.async_schedule_restart_addon(catch_error=True) assert "Failed to restart the Test add-on: Boom" in caplog.text assert restart_addon.call_count == 1 async def test_stop_addon(addon_manager: AddonManager, stop_addon: AsyncMock) -> None: """Test stop addon.""" await addon_manager.async_stop_addon() assert stop_addon.call_count == 1 async def test_stop_addon_error( addon_manager: AddonManager, stop_addon: AsyncMock ) -> None: """Test stop addon raises error.""" stop_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_stop_addon() assert str(err.value) == "Failed to stop the Test add-on: Boom" assert stop_addon.call_count == 1 async def test_update_addon( hass: HomeAssistant, addon_manager: AddonManager, addon_info: AsyncMock, addon_installed: AsyncMock, create_backup: AsyncMock, update_addon: AsyncMock, ) -> None: """Test update addon.""" addon_info.return_value["update_available"] = True await addon_manager.async_update_addon() assert addon_info.call_count == 2 assert create_backup.call_count == 1 assert create_backup.call_args == call( hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True ) assert update_addon.call_count == 1 async def test_update_addon_no_update( addon_manager: AddonManager, addon_info: AsyncMock, addon_installed: AsyncMock, create_backup: AsyncMock, update_addon: AsyncMock, ) -> None: """Test update addon without update available.""" addon_info.return_value["update_available"] = False await addon_manager.async_update_addon() assert addon_info.call_count == 1 assert create_backup.call_count == 0 assert update_addon.call_count == 0 async def test_update_addon_error( hass: HomeAssistant, addon_manager: AddonManager, addon_info: AsyncMock, addon_installed: AsyncMock, create_backup: AsyncMock, update_addon: AsyncMock, ) -> None: """Test update addon raises error.""" addon_info.return_value["update_available"] = True update_addon.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_update_addon() assert str(err.value) == "Failed to update the Test add-on: Boom" assert addon_info.call_count == 2 assert create_backup.call_count == 1 assert create_backup.call_args == call( hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True ) assert update_addon.call_count == 1 async def test_schedule_update_addon( hass: HomeAssistant, addon_manager: AddonManager, addon_info: AsyncMock, addon_installed: AsyncMock, create_backup: AsyncMock, update_addon: AsyncMock, ) -> None: """Test schedule update addon.""" addon_info.return_value["update_available"] = True update_task = addon_manager.async_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, update_available=True, version="1.0.0", ) # Make sure that actually only one update task is running. update_task_two = addon_manager.async_schedule_update_addon() await asyncio.gather(update_task, update_task_two) assert addon_manager.task_in_progress() is False assert addon_info.call_count == 3 assert create_backup.call_count == 1 assert create_backup.call_args == call( hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True ) assert update_addon.call_count == 1 update_addon.reset_mock() # Test that another call can be made after the update is done. await addon_manager.async_schedule_update_addon() assert update_addon.call_count == 1 @pytest.mark.parametrize( ( "create_backup_error", "create_backup_calls", "update_addon_error", "update_addon_calls", "error_message", ), [ ( HassioAPIError("Boom"), 1, None, 0, "Failed to create a backup of the Test add-on: Boom", ), ( None, 1, HassioAPIError("Boom"), 1, "Failed to update the Test add-on: Boom", ), ], ) async def test_schedule_update_addon_error( addon_manager: AddonManager, addon_installed: AsyncMock, create_backup: AsyncMock, update_addon: AsyncMock, create_backup_error: Exception | None, create_backup_calls: int, update_addon_error: Exception | None, update_addon_calls: int, error_message: str, ) -> None: """Test schedule update addon raises error.""" addon_installed.return_value["update_available"] = True create_backup.side_effect = create_backup_error update_addon.side_effect = update_addon_error with pytest.raises(AddonError) as err: await addon_manager.async_schedule_update_addon() assert str(err.value) == error_message assert create_backup.call_count == create_backup_calls assert update_addon.call_count == update_addon_calls @pytest.mark.parametrize( ( "create_backup_error", "create_backup_calls", "update_addon_error", "update_addon_calls", "error_log", ), [ ( HassioAPIError("Boom"), 1, None, 0, "Failed to create a backup of the Test add-on: Boom", ), ( None, 1, HassioAPIError("Boom"), 1, "Failed to update the Test add-on: Boom", ), ], ) async def test_schedule_update_addon_logs_error( addon_manager: AddonManager, addon_installed: AsyncMock, create_backup: AsyncMock, update_addon: AsyncMock, create_backup_error: Exception | None, create_backup_calls: int, update_addon_error: Exception | None, update_addon_calls: int, error_log: str, caplog: pytest.LogCaptureFixture, ) -> None: """Test schedule update addon logs error.""" addon_installed.return_value["update_available"] = True create_backup.side_effect = create_backup_error update_addon.side_effect = update_addon_error await addon_manager.async_schedule_update_addon(catch_error=True) assert error_log in caplog.text assert create_backup.call_count == create_backup_calls assert update_addon.call_count == update_addon_calls async def test_create_backup( hass: HomeAssistant, addon_manager: AddonManager, addon_info: AsyncMock, addon_installed: AsyncMock, create_backup: AsyncMock, ) -> None: """Test creating a backup of the addon.""" await addon_manager.async_create_backup() assert addon_info.call_count == 1 assert create_backup.call_count == 1 assert create_backup.call_args == call( hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True ) async def test_create_backup_error( hass: HomeAssistant, addon_manager: AddonManager, addon_info: AsyncMock, addon_installed: AsyncMock, create_backup: AsyncMock, ) -> None: """Test creating a backup of the addon raises error.""" create_backup.side_effect = HassioAPIError("Boom") with pytest.raises(AddonError) as err: await addon_manager.async_create_backup() assert str(err.value) == "Failed to create a backup of the Test add-on: Boom" assert addon_info.call_count == 1 assert create_backup.call_count == 1 assert create_backup.call_args == call( hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True ) async def test_schedule_install_setup_addon( addon_manager: AddonManager, addon_installed: AsyncMock, install_addon: AsyncMock, set_addon_options: AsyncMock, start_addon: AsyncMock, ) -> None: """Test schedule install setup addon.""" install_task = addon_manager.async_schedule_install_setup_addon( {"test_key": "test"} ) assert addon_manager.task_in_progress() is True # Make sure that actually only one install task is running. install_task_two = addon_manager.async_schedule_install_setup_addon( {"test_key": "test"} ) await asyncio.gather(install_task, install_task_two) assert addon_manager.task_in_progress() is False assert install_addon.call_count == 1 assert set_addon_options.call_count == 1 assert start_addon.call_count == 1 install_addon.reset_mock() set_addon_options.reset_mock() start_addon.reset_mock() # Test that another call can be made after the install is done. await addon_manager.async_schedule_install_setup_addon({"test_key": "test"}) assert install_addon.call_count == 1 assert set_addon_options.call_count == 1 assert start_addon.call_count == 1 @pytest.mark.parametrize( ( "install_addon_error", "install_addon_calls", "set_addon_options_error", "set_addon_options_calls", "start_addon_error", "start_addon_calls", "error_message", ), [ ( HassioAPIError("Boom"), 1, None, 0, None, 0, "Failed to install the Test add-on: Boom", ), ( None, 1, HassioAPIError("Boom"), 1, None, 0, "Failed to set the Test add-on options: Boom", ), ( None, 1, None, 1, HassioAPIError("Boom"), 1, "Failed to start the Test add-on: Boom", ), ], ) async def test_schedule_install_setup_addon_error( addon_manager: AddonManager, addon_installed: AsyncMock, install_addon: AsyncMock, set_addon_options: AsyncMock, start_addon: AsyncMock, install_addon_error: Exception | None, install_addon_calls: int, set_addon_options_error: Exception | None, set_addon_options_calls: int, start_addon_error: Exception | None, start_addon_calls: int, error_message: str, ) -> None: """Test schedule install setup addon raises error.""" install_addon.side_effect = install_addon_error set_addon_options.side_effect = set_addon_options_error start_addon.side_effect = start_addon_error with pytest.raises(AddonError) as err: await addon_manager.async_schedule_install_setup_addon({"test_key": "test"}) assert str(err.value) == error_message assert install_addon.call_count == install_addon_calls assert set_addon_options.call_count == set_addon_options_calls assert start_addon.call_count == start_addon_calls @pytest.mark.parametrize( ( "install_addon_error", "install_addon_calls", "set_addon_options_error", "set_addon_options_calls", "start_addon_error", "start_addon_calls", "error_log", ), [ ( HassioAPIError("Boom"), 1, None, 0, None, 0, "Failed to install the Test add-on: Boom", ), ( None, 1, HassioAPIError("Boom"), 1, None, 0, "Failed to set the Test add-on options: Boom", ), ( None, 1, None, 1, HassioAPIError("Boom"), 1, "Failed to start the Test add-on: Boom", ), ], ) async def test_schedule_install_setup_addon_logs_error( addon_manager: AddonManager, addon_installed: AsyncMock, install_addon: AsyncMock, set_addon_options: AsyncMock, start_addon: AsyncMock, install_addon_error: Exception | None, install_addon_calls: int, set_addon_options_error: Exception | None, set_addon_options_calls: int, start_addon_error: Exception | None, start_addon_calls: int, error_log: str, caplog: pytest.LogCaptureFixture, ) -> None: """Test schedule install setup addon logs error.""" install_addon.side_effect = install_addon_error set_addon_options.side_effect = set_addon_options_error start_addon.side_effect = start_addon_error await addon_manager.async_schedule_install_setup_addon( {"test_key": "test"}, catch_error=True ) assert error_log in caplog.text assert install_addon.call_count == install_addon_calls assert set_addon_options.call_count == set_addon_options_calls assert start_addon.call_count == start_addon_calls async def test_schedule_setup_addon( addon_manager: AddonManager, addon_installed: AsyncMock, set_addon_options: AsyncMock, start_addon: AsyncMock, ) -> None: """Test schedule setup addon.""" start_task = addon_manager.async_schedule_setup_addon({"test_key": "test"}) assert addon_manager.task_in_progress() is True # Make sure that actually only one start task is running. start_task_two = addon_manager.async_schedule_setup_addon({"test_key": "test"}) await asyncio.gather(start_task, start_task_two) assert addon_manager.task_in_progress() is False assert set_addon_options.call_count == 1 assert start_addon.call_count == 1 set_addon_options.reset_mock() start_addon.reset_mock() # Test that another call can be made after the start is done. await addon_manager.async_schedule_setup_addon({"test_key": "test"}) assert set_addon_options.call_count == 1 assert start_addon.call_count == 1 @pytest.mark.parametrize( ( "set_addon_options_error", "set_addon_options_calls", "start_addon_error", "start_addon_calls", "error_message", ), [ ( HassioAPIError("Boom"), 1, None, 0, "Failed to set the Test add-on options: Boom", ), ( None, 1, HassioAPIError("Boom"), 1, "Failed to start the Test add-on: Boom", ), ], ) async def test_schedule_setup_addon_error( addon_manager: AddonManager, addon_installed: AsyncMock, set_addon_options: AsyncMock, start_addon: AsyncMock, set_addon_options_error: Exception | None, set_addon_options_calls: int, start_addon_error: Exception | None, start_addon_calls: int, error_message: str, ) -> None: """Test schedule setup addon raises error.""" set_addon_options.side_effect = set_addon_options_error start_addon.side_effect = start_addon_error with pytest.raises(AddonError) as err: await addon_manager.async_schedule_setup_addon({"test_key": "test"}) assert str(err.value) == error_message assert set_addon_options.call_count == set_addon_options_calls assert start_addon.call_count == start_addon_calls @pytest.mark.parametrize( ( "set_addon_options_error", "set_addon_options_calls", "start_addon_error", "start_addon_calls", "error_log", ), [ ( HassioAPIError("Boom"), 1, None, 0, "Failed to set the Test add-on options: Boom", ), ( None, 1, HassioAPIError("Boom"), 1, "Failed to start the Test add-on: Boom", ), ], ) async def test_schedule_setup_addon_logs_error( addon_manager: AddonManager, addon_installed: AsyncMock, set_addon_options: AsyncMock, start_addon: AsyncMock, set_addon_options_error: Exception | None, set_addon_options_calls: int, start_addon_error: Exception | None, start_addon_calls: int, error_log: str, caplog: pytest.LogCaptureFixture, ) -> None: """Test schedule setup addon logs error.""" set_addon_options.side_effect = set_addon_options_error start_addon.side_effect = start_addon_error await addon_manager.async_schedule_setup_addon( {"test_key": "test"}, catch_error=True ) assert error_log in caplog.text assert set_addon_options.call_count == set_addon_options_calls assert start_addon.call_count == start_addon_calls