"""Tests for the PS4 Integration.""" from unittest.mock import MagicMock, patch from homeassistant import config_entries, data_entry_flow from homeassistant.components import ps4 from homeassistant.components.media_player import ( ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_TITLE, MediaType, ) from homeassistant.components.ps4.const import ( ATTR_MEDIA_IMAGE_URL, COMMANDS, CONFIG_ENTRY_VERSION as VERSION, DEFAULT_REGION, DOMAIN, PS4_DATA, ) from homeassistant.const import ( ATTR_COMMAND, ATTR_ENTITY_ID, ATTR_LOCKED, CONF_HOST, CONF_NAME, CONF_REGION, CONF_TOKEN, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from homeassistant.util import location from tests.common import MockConfigEntry MOCK_HOST = "192.168.0.1" MOCK_NAME = "test_ps4" MOCK_REGION = "Some Region" MOCK_CREDS = "1234567890A" MOCK_DEVICE = {CONF_HOST: MOCK_HOST, CONF_NAME: MOCK_NAME, CONF_REGION: MOCK_REGION} MOCK_DATA = {CONF_TOKEN: MOCK_CREDS, "devices": [MOCK_DEVICE]} MOCK_FLOW_RESULT = { "version": VERSION, "handler": DOMAIN, "type": data_entry_flow.FlowResultType.CREATE_ENTRY, "title": "test_ps4", "data": MOCK_DATA, "options": {}, } MOCK_ENTRY_ID = "SomeID" MOCK_CONFIG = MockConfigEntry(domain=DOMAIN, data=MOCK_DATA, entry_id=MOCK_ENTRY_ID) MOCK_LOCATION = location.LocationInfo( "0.0.0.0", "US", "USD", "CA", "California", "San Diego", "92122", "America/Los_Angeles", 32.8594, -117.2073, True, ) MOCK_DEVICE_VERSION_1 = { CONF_HOST: MOCK_HOST, CONF_NAME: MOCK_NAME, CONF_REGION: "Some Region", } MOCK_DATA_VERSION_1 = {CONF_TOKEN: MOCK_CREDS, "devices": [MOCK_DEVICE_VERSION_1]} MOCK_DEVICE_ID = "somedeviceid" MOCK_ENTRY_VERSION_1 = MockConfigEntry( domain=DOMAIN, data=MOCK_DATA_VERSION_1, entry_id=MOCK_ENTRY_ID, version=1 ) MOCK_UNIQUE_ID = "someuniqueid" MOCK_ID = "CUSA00123" MOCK_URL = "http://someurl.jpeg" MOCK_TITLE = "Some Title" MOCK_TYPE = MediaType.GAME MOCK_GAMES_DATA_OLD_STR_FORMAT = {"mock_id": "mock_title", "mock_id2": "mock_title2"} MOCK_GAMES_DATA = { ATTR_LOCKED: False, ATTR_MEDIA_CONTENT_TYPE: MediaType.GAME, ATTR_MEDIA_IMAGE_URL: MOCK_URL, ATTR_MEDIA_TITLE: MOCK_TITLE, } MOCK_GAMES_DATA_LOCKED = { ATTR_LOCKED: True, ATTR_MEDIA_CONTENT_TYPE: MediaType.GAME, ATTR_MEDIA_IMAGE_URL: MOCK_URL, ATTR_MEDIA_TITLE: MOCK_TITLE, } MOCK_GAMES = {MOCK_ID: MOCK_GAMES_DATA} MOCK_GAMES_LOCKED = {MOCK_ID: MOCK_GAMES_DATA_LOCKED} async def test_ps4_integration_setup(hass: HomeAssistant) -> None: """Test PS4 integration is setup.""" await ps4.async_setup(hass, {}) await hass.async_block_till_done() assert hass.data[PS4_DATA].protocol is not None async def test_creating_entry_sets_up_media_player(hass: HomeAssistant) -> None: """Test setting up PS4 loads the media player.""" mock_flow = "homeassistant.components.ps4.PlayStation4FlowHandler.async_step_user" with patch( "homeassistant.components.ps4.media_player.async_setup_entry", return_value=True, ) as mock_setup, patch(mock_flow, return_value=MOCK_FLOW_RESULT): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER} ) assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 async def test_config_flow_entry_migrate( hass: HomeAssistant, entity_registry: er.EntityRegistry ) -> None: """Test that config flow entry is migrated correctly.""" # Start with the config entry at Version 1. manager = hass.config_entries mock_entry = MOCK_ENTRY_VERSION_1 mock_entry.add_to_manager(manager) mock_entity_id = f"media_player.ps4_{MOCK_UNIQUE_ID}" mock_e_entry = entity_registry.async_get_or_create( "media_player", "ps4", MOCK_UNIQUE_ID, config_entry=mock_entry, device_id=MOCK_DEVICE_ID, ) assert len(entity_registry.entities) == 1 assert mock_e_entry.entity_id == mock_entity_id assert mock_e_entry.unique_id == MOCK_UNIQUE_ID with patch( "homeassistant.util.location.async_detect_location_info", return_value=MOCK_LOCATION, ), patch( "homeassistant.helpers.entity_registry.async_get", return_value=entity_registry, ): await ps4.async_migrate_entry(hass, mock_entry) await hass.async_block_till_done() assert len(entity_registry.entities) == 1 for entity in entity_registry.entities.values(): mock_entity = entity # Test that entity_id remains the same. assert mock_entity.entity_id == mock_entity_id assert mock_entity.device_id == MOCK_DEVICE_ID # Test that last four of credentials is appended to the unique_id. assert mock_entity.unique_id == f"{MOCK_UNIQUE_ID}_{MOCK_CREDS[-4:]}" # Test that config entry is at the current version. assert mock_entry.version == VERSION assert mock_entry.data[CONF_TOKEN] == MOCK_CREDS assert mock_entry.data["devices"][0][CONF_HOST] == MOCK_HOST assert mock_entry.data["devices"][0][CONF_NAME] == MOCK_NAME assert mock_entry.data["devices"][0][CONF_REGION] == DEFAULT_REGION async def test_media_player_is_setup(hass: HomeAssistant) -> None: """Test media_player is setup correctly.""" await setup_mock_component(hass) assert len(hass.data[PS4_DATA].devices) == 1 async def setup_mock_component(hass): """Set up Mock Media Player.""" entry = MockConfigEntry(domain=ps4.DOMAIN, data=MOCK_DATA, version=VERSION) entry.add_to_manager(hass.config_entries) await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) await hass.async_block_till_done() def test_games_reformat_to_dict( hass: HomeAssistant, patch_load_json_object: MagicMock ) -> None: """Test old data format is converted to new format.""" patch_load_json_object.return_value = MOCK_GAMES_DATA_OLD_STR_FORMAT with patch( "homeassistant.components.ps4.save_json", side_effect=MagicMock() ), patch("os.path.isfile", return_value=True): mock_games = ps4.load_games(hass, MOCK_ENTRY_ID) # New format is a nested dict. assert isinstance(mock_games, dict) assert mock_games["mock_id"][ATTR_MEDIA_TITLE] == "mock_title" assert mock_games["mock_id2"][ATTR_MEDIA_TITLE] == "mock_title2" for mock_game in mock_games: mock_data = mock_games[mock_game] assert isinstance(mock_data, dict) assert mock_data assert mock_data[ATTR_MEDIA_IMAGE_URL] is None assert mock_data[ATTR_LOCKED] is False assert mock_data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.GAME def test_load_games(hass: HomeAssistant, patch_load_json_object: MagicMock) -> None: """Test that games are loaded correctly.""" patch_load_json_object.return_value = MOCK_GAMES with patch( "homeassistant.components.ps4.save_json", side_effect=MagicMock() ), patch("os.path.isfile", return_value=True): mock_games = ps4.load_games(hass, MOCK_ENTRY_ID) assert isinstance(mock_games, dict) mock_data = mock_games[MOCK_ID] assert isinstance(mock_data, dict) assert mock_data[ATTR_MEDIA_TITLE] == MOCK_TITLE assert mock_data[ATTR_MEDIA_IMAGE_URL] == MOCK_URL assert mock_data[ATTR_LOCKED] is False assert mock_data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.GAME def test_loading_games_returns_dict( hass: HomeAssistant, patch_load_json_object: MagicMock ) -> None: """Test that loading games always returns a dict.""" patch_load_json_object.side_effect = HomeAssistantError with patch( "homeassistant.components.ps4.save_json", side_effect=MagicMock() ), patch("os.path.isfile", return_value=True): mock_games = ps4.load_games(hass, MOCK_ENTRY_ID) assert isinstance(mock_games, dict) assert not mock_games async def test_send_command(hass: HomeAssistant) -> None: """Test send_command service.""" await setup_mock_component(hass) mock_func = "{}{}".format( "homeassistant.components.ps4", ".media_player.PS4Device.async_send_command" ) mock_devices = hass.data[PS4_DATA].devices assert len(mock_devices) == 1 mock_entity = mock_devices[0] assert mock_entity.entity_id == f"media_player.{MOCK_NAME}" # Test that all commands call service function. with patch(mock_func, return_value=True) as mock_service: for mock_command in COMMANDS: await hass.services.async_call( DOMAIN, "send_command", {ATTR_ENTITY_ID: mock_entity.entity_id, ATTR_COMMAND: mock_command}, ) await hass.async_block_till_done() assert len(mock_service.mock_calls) == len(COMMANDS)