"""Tests for the Xbox integration.""" from datetime import timedelta from unittest.mock import AsyncMock, patch from freezegun.api import FrozenDateTimeFactory from httpx import ConnectTimeout, HTTPStatusError, ProtocolError import pytest from pythonxbox.api.provider.smartglass.models import SmartglassConsoleList from homeassistant.components.xbox.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from homeassistant.helpers.config_entry_oauth2_flow import ( ImplementationUnavailableError, ) from tests.common import ( MockConfigEntry, async_fire_time_changed, async_load_json_object_fixture, ) @pytest.mark.usefixtures("xbox_live_client") async def test_entry_setup_unload( hass: HomeAssistant, config_entry: MockConfigEntry ) -> None: """Test integration setup and unload.""" config_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED assert await hass.config_entries.async_unload(config_entry.entry_id) assert config_entry.state is ConfigEntryState.NOT_LOADED @pytest.mark.parametrize( "exception", [ConnectTimeout, HTTPStatusError, ProtocolError], ) async def test_config_entry_not_ready( hass: HomeAssistant, config_entry: MockConfigEntry, xbox_live_client: AsyncMock, exception: Exception, ) -> None: """Test config entry not ready.""" xbox_live_client.smartglass.get_console_list.side_effect = exception config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.SETUP_RETRY @pytest.mark.usefixtures("xbox_live_client") async def test_config_implementation_not_available( hass: HomeAssistant, config_entry: MockConfigEntry, ) -> None: """Test implementation not available.""" config_entry.add_to_hass(hass) with patch( "homeassistant.components.xbox.async_get_config_entry_implementation", side_effect=ImplementationUnavailableError, ): await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.SETUP_RETRY @pytest.mark.parametrize("exception", [ConnectTimeout, HTTPStatusError, ProtocolError]) @pytest.mark.parametrize( ("provider", "method"), [ ("smartglass", "get_console_status"), ("catalog", "get_product_from_alternate_id"), ("people", "get_friends_by_xuid"), ("people", "get_friends_own"), ], ) async def test_coordinator_update_failed( hass: HomeAssistant, config_entry: MockConfigEntry, xbox_live_client: AsyncMock, exception: Exception, provider: str, method: str, ) -> None: """Test coordinator update failed.""" provider = getattr(xbox_live_client, provider) getattr(provider, method).side_effect = exception config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.SETUP_RETRY @pytest.mark.freeze_time async def test_dynamic_devices( hass: HomeAssistant, config_entry: MockConfigEntry, xbox_live_client: AsyncMock, device_registry: dr.DeviceRegistry, freezer: FrozenDateTimeFactory, ) -> None: """Test adding of new and removal of stale devices at runtime.""" xbox_live_client.smartglass.get_console_list.return_value = SmartglassConsoleList( **await async_load_json_object_fixture( hass, "smartglass_console_list_empty.json", DOMAIN ) # pyright: ignore[reportArgumentType] ) config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED assert device_registry.async_get_device({(DOMAIN, "ABCDEFG")}) is None assert device_registry.async_get_device({(DOMAIN, "HIJKLMN")}) is None xbox_live_client.smartglass.get_console_list.return_value = SmartglassConsoleList( **await async_load_json_object_fixture( hass, "smartglass_console_list.json", DOMAIN ) # pyright: ignore[reportArgumentType] ) freezer.tick(timedelta(minutes=10)) async_fire_time_changed(hass) await hass.async_block_till_done() assert device_registry.async_get_device({(DOMAIN, "ABCDEFG")}) assert device_registry.async_get_device({(DOMAIN, "HIJKLMN")}) xbox_live_client.smartglass.get_console_list.return_value = SmartglassConsoleList( **await async_load_json_object_fixture( hass, "smartglass_console_list_empty.json", DOMAIN ) # pyright: ignore[reportArgumentType] ) freezer.tick(timedelta(minutes=10)) async_fire_time_changed(hass) await hass.async_block_till_done() assert device_registry.async_get_device({(DOMAIN, "ABCDEFG")}) is None assert device_registry.async_get_device({(DOMAIN, "HIJKLMN")}) is None