diff --git a/.coveragerc b/.coveragerc index 76dc1e933ec..34cf79ad958 100644 --- a/.coveragerc +++ b/.coveragerc @@ -119,7 +119,6 @@ omit = homeassistant/components/buienradar/weather.py homeassistant/components/caldav/calendar.py homeassistant/components/canary/camera.py - homeassistant/components/cast/* homeassistant/components/cert_expiry/helper.py homeassistant/components/channels/* homeassistant/components/circuit/* diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 86b61d8f687..0e9f6c13e3d 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -1,5 +1,6 @@ """The tests for the Cast Media player platform.""" # pylint: disable=protected-access +import json from typing import Optional from uuid import UUID @@ -15,12 +16,25 @@ from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.typing import HomeAssistantType from homeassistant.setup import async_setup_component -from tests.async_mock import AsyncMock, MagicMock, Mock, patch +from tests.async_mock import ANY, AsyncMock, MagicMock, Mock, patch from tests.common import MockConfigEntry, assert_setup_component +from tests.components.media_player import common + + +@pytest.fixture() +def mz_mock(): + """Mock pychromecast MultizoneManager.""" + return MagicMock() + + +@pytest.fixture() +def quick_play_mock(): + """Mock pychromecast quick_play.""" + return MagicMock() @pytest.fixture(autouse=True) -def cast_mock(): +def cast_mock(mz_mock, quick_play_mock): """Mock pychromecast.""" pycast_mock = MagicMock() pycast_mock.start_discovery.return_value = (None, Mock()) @@ -35,10 +49,14 @@ def cast_mock(): ), patch( "homeassistant.components.cast.discovery.pychromecast", pycast_mock ), patch( - "homeassistant.components.cast.media_player.MultizoneManager", MagicMock() + "homeassistant.components.cast.media_player.MultizoneManager", + return_value=mz_mock, ), patch( "homeassistant.components.cast.media_player.zeroconf.async_get_instance", AsyncMock(), + ), patch( + "homeassistant.components.cast.media_player.quick_play", + quick_play_mock, ): yield @@ -133,8 +151,6 @@ async def async_setup_media_player_cast(hass: HomeAssistantType, info: Chromecas chromecast = get_fake_chromecast(info) zconf = get_fake_zconf(host=info.host, port=info.port) - cast.CastStatusListener = MagicMock() - with patch( "homeassistant.components.cast.discovery.pychromecast.get_chromecast_from_service", return_value=chromecast, @@ -153,27 +169,40 @@ async def async_setup_media_player_cast(hass: HomeAssistantType, info: Chromecas ) await hass.async_block_till_done() - await cast.async_setup_entry(hass, MockConfigEntry(), None) - discovery_callback = cast_listener.call_args[0][0] - def discover_chromecast(service_name: str, info: ChromecastInfo) -> None: - """Discover a chromecast device.""" - listener.services[info.uuid] = ( - {service_name}, - info.uuid, - info.model_name, - info.friendly_name, - ) - discovery_callback(info.uuid, service_name) + service_name = "the-service" + listener.services[info.uuid] = ( + {service_name}, + info.uuid, + info.model_name, + info.friendly_name, + ) + discovery_callback(info.uuid, service_name) - discover_chromecast("the-service", info) await hass.async_block_till_done() await hass.async_block_till_done() assert get_chromecast.call_count == 1 - assert cast.CastStatusListener.call_count == 1 - entity = cast.CastStatusListener.call_args[0][0] - return chromecast, entity + return chromecast + + +def get_status_callbacks(chromecast_mock, mz_mock=None): + """Get registered status callbacks from the chromecast mock.""" + status_listener = chromecast_mock.register_status_listener.call_args[0][0] + cast_status_cb = status_listener.new_cast_status + + connection_listener = chromecast_mock.register_connection_listener.call_args[0][0] + conn_status_cb = connection_listener.new_connection_status + + mc = chromecast_mock.socket_client.media_controller + media_status_cb = mc.register_status_listener.call_args[0][0].new_media_status + + if not mz_mock: + return cast_status_cb, conn_status_cb, media_status_cb + + mz_listener = mz_mock.register_listener.call_args[0][1] + group_media_status_cb = mz_listener.multizone_new_media_status + return cast_status_cb, conn_status_cb, media_status_cb, group_media_status_cb async def test_start_discovery_called_once(hass): @@ -358,78 +387,429 @@ async def test_update_cast_chromecasts(hass): assert add_dev1.call_count == 1 -async def test_entity_media_states(hass: HomeAssistantType): - """Test various entity media states.""" +async def test_entity_availability(hass: HomeAssistantType): + """Test handling of connection status.""" + entity_id = "media_player.speaker" + info = get_fake_chromecast_info() + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + state = hass.states.get(entity_id) + assert state.state == "unavailable" + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.state == "unknown" + + connection_status = MagicMock() + connection_status.status = "DISCONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.state == "unavailable" + + +async def test_entity_cast_status(hass: HomeAssistantType): + """Test handling of cast status.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + cast_status_cb, conn_status_cb, _ = get_status_callbacks(chromecast) - entity._available = True - entity.schedule_update_ha_state() + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + cast_status = MagicMock() + cast_status.volume_level = 0.5 + cast_status.volume_muted = False + cast_status_cb(cast_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("volume_level") == 0.5 + assert not state.attributes.get("is_volume_muted") + + cast_status = MagicMock() + cast_status.volume_level = 0.2 + cast_status.volume_muted = True + cast_status_cb(cast_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("volume_level") == 0.2 + assert state.attributes.get("is_volume_muted") + + +async def test_entity_play_media(hass: HomeAssistantType): + """Test playing media.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # Play_media + await common.async_play_media(hass, "audio", "best.mp3", entity_id) + chromecast.media_controller.play_media.assert_called_once_with("best.mp3", "audio") + + +async def test_entity_play_media_cast(hass: HomeAssistantType, quick_play_mock): + """Test playing media with cast special features.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # Play_media - cast with app ID + await common.async_play_media(hass, "cast", '{"app_id": "abc123"}', entity_id) + chromecast.start_app.assert_called_once_with("abc123") + + # Play_media - cast with app name (quick play) + await common.async_play_media(hass, "cast", '{"app_name": "youtube"}', entity_id) + quick_play_mock.assert_called_once_with(ANY, "youtube", {}) + + +async def test_entity_play_media_cast_invalid(hass, caplog, quick_play_mock): + """Test playing media.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # play_media - media_type cast with invalid JSON + with pytest.raises(json.decoder.JSONDecodeError): + await common.async_play_media(hass, "cast", '{"app_id": "abc123"', entity_id) + assert "Invalid JSON in media_content_id" in caplog.text + chromecast.start_app.assert_not_called() + quick_play_mock.assert_not_called() + + # Play_media - media_type cast with extra keys + await common.async_play_media( + hass, "cast", '{"app_id": "abc123", "extra": "data"}', entity_id + ) + assert "Extra keys dict_keys(['extra']) were ignored" in caplog.text + chromecast.start_app.assert_called_once_with("abc123") + quick_play_mock.assert_not_called() + + # Play_media - media_type cast with unsupported app + quick_play_mock.side_effect = NotImplementedError() + await common.async_play_media(hass, "cast", '{"app_name": "unknown"}', entity_id) + quick_play_mock.assert_called_once_with(ANY, "unknown", {}) + assert "App unknown not supported" in caplog.text + + +async def test_entity_play_media_sign_URL(hass: HomeAssistantType): + """Test playing media.""" + entity_id = "media_player.speaker" + + await async_process_ha_core_config( + hass, + {"external_url": "http://example.com:8123"}, + ) + + info = get_fake_chromecast_info() + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, _ = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + # Play_media + await common.async_play_media(hass, "audio", "/best.mp3", entity_id) + chromecast.media_controller.play_media.assert_called_once_with(ANY, "audio") + assert chromecast.media_controller.play_media.call_args[0][0].startswith( + "http://example.com:8123/best.mp3?authSig=" + ) + + +async def test_entity_media_content_type(hass: HomeAssistantType): + """Test various content types.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + media_status = MagicMock(images=None) + media_status.media_is_movie = False + media_status.media_is_musictrack = False + media_status.media_is_tvshow = False + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") is None + + media_status.media_is_tvshow = True + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") == "tvshow" + + media_status.media_is_tvshow = False + media_status.media_is_musictrack = True + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") == "music" + + media_status.media_is_musictrack = True + media_status.media_is_movie = True + media_status_cb(media_status) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.attributes.get("media_content_type") == "movie" + + +async def test_entity_control(hass: HomeAssistantType): + """Test various device and media controls.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) + + # Turn on + await common.async_turn_on(hass, entity_id) + chromecast.play_media.assert_called_once_with( + "https://www.home-assistant.io/images/cast/splash.png", ANY + ) + chromecast.quit_app.reset_mock() + + # Turn off + await common.async_turn_off(hass, entity_id) + chromecast.quit_app.assert_called_once_with() + + # Mute + await common.async_mute_volume(hass, True, entity_id) + chromecast.set_volume_muted.assert_called_once_with(True) + + # Volume + await common.async_set_volume_level(hass, 0.33, entity_id) + chromecast.set_volume.assert_called_once_with(0.33) + + # Media play + await common.async_media_play(hass, entity_id) + chromecast.media_controller.play.assert_called_once_with() + + # Media pause + await common.async_media_pause(hass, entity_id) + chromecast.media_controller.pause.assert_called_once_with() + + # Media previous + await common.async_media_previous_track(hass, entity_id) + chromecast.media_controller.queue_prev.assert_not_called() + + # Media next + await common.async_media_next_track(hass, entity_id) + chromecast.media_controller.queue_next.assert_not_called() + + # Media seek + await common.async_media_seek(hass, 123, entity_id) + chromecast.media_controller.seek.assert_not_called() + + # Enable support for queue and seek + media_status = MagicMock(images=None) + media_status.supports_queue_next = True + media_status.supports_seek = True + media_status_cb(media_status) + await hass.async_block_till_done() + + # Media previous + await common.async_media_previous_track(hass, entity_id) + chromecast.media_controller.queue_prev.assert_called_once_with() + + # Media next + await common.async_media_next_track(hass, entity_id) + chromecast.media_controller.queue_next.assert_called_once_with() + + # Media seek + await common.async_media_seek(hass, 123, entity_id) + chromecast.media_controller.seek.assert_called_once_with(123) + + +async def test_entity_media_states(hass: HomeAssistantType): + """Test various entity media states.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + + info = get_fake_chromecast_info() + full_info = attr.evolve( + info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID + ) + + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) + + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state is not None + assert state.name == "Speaker" + assert state.state == "unknown" + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) media_status = MagicMock(images=None) media_status.player_is_playing = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "playing" media_status.player_is_playing = False media_status.player_is_paused = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "paused" media_status.player_is_paused = False media_status.player_is_idle = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "idle" media_status.player_is_idle = False chromecast.is_idle = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "off" chromecast.is_idle = False - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "unknown" async def test_url_replace(hass: HomeAssistantType): """Test functionality of replacing URL for HTTPS.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) - entity._available = True - entity.schedule_update_ha_state() + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) class FakeHTTPImage: url = "http://example.com/test.png" @@ -439,112 +819,128 @@ async def test_url_replace(hass: HomeAssistantType): media_status = MagicMock(images=[FakeHTTPImage()]) media_status.player_is_playing = True - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.attributes.get("entity_picture") == "//example.com/test.png" media_status.images = [FakeHTTPSImage()] - entity.new_media_status(media_status) + media_status_cb(media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.attributes.get("entity_picture") == "https://example.com/test.png" -async def test_group_media_states(hass: HomeAssistantType): +async def test_group_media_states(hass, mz_mock): """Test media states are read from group if entity has no state.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, conn_status_cb, media_status_cb, group_media_status_cb = get_status_callbacks( + chromecast, mz_mock + ) - entity._available = True - entity.schedule_update_ha_state() + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) group_media_status = MagicMock(images=None) player_media_status = MagicMock(images=None) # Player has no state, group is playing -> Should report 'playing' group_media_status.player_is_playing = True - entity.multizone_new_media_status(str(FakeGroupUUID), group_media_status) + group_media_status_cb(str(FakeGroupUUID), group_media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "playing" # Player is paused, group is playing -> Should report 'paused' player_media_status.player_is_playing = False player_media_status.player_is_paused = True - entity.new_media_status(player_media_status) + media_status_cb(player_media_status) await hass.async_block_till_done() await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "paused" # Player is in unknown state, group is playing -> Should report 'playing' player_media_status.player_state = "UNKNOWN" - entity.new_media_status(player_media_status) + media_status_cb(player_media_status) await hass.async_block_till_done() - state = hass.states.get("media_player.speaker") + state = hass.states.get(entity_id) assert state.state == "playing" -async def test_group_media_control(hass: HomeAssistantType): +async def test_group_media_control(hass, mz_mock): """Test media states are read from group if entity has no state.""" + entity_id = "media_player.speaker" + reg = await hass.helpers.entity_registry.async_get_registry() + info = get_fake_chromecast_info() full_info = attr.evolve( info, model_name="google home", friendly_name="Speaker", uuid=FakeUUID ) - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) - entity._available = True - entity.async_write_ha_state() + _, conn_status_cb, media_status_cb, group_media_status_cb = get_status_callbacks( + chromecast, mz_mock + ) - state = hass.states.get("media_player.speaker") + connection_status = MagicMock() + connection_status.status = "CONNECTED" + conn_status_cb(connection_status) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) assert state is not None assert state.name == "Speaker" assert state.state == "unknown" - assert entity.unique_id == full_info.uuid + assert entity_id == reg.async_get_entity_id("media_player", "cast", full_info.uuid) group_media_status = MagicMock(images=None) player_media_status = MagicMock(images=None) # Player has no state, group is playing -> Should forward calls to group group_media_status.player_is_playing = True - entity.multizone_new_media_status(str(FakeGroupUUID), group_media_status) - entity.media_play() - grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + group_media_status_cb(str(FakeGroupUUID), group_media_status) + await common.async_media_play(hass, entity_id) + grp_media = mz_mock.get_multizone_mediacontroller(str(FakeGroupUUID)) assert grp_media.play.called assert not chromecast.media_controller.play.called # Player is paused, group is playing -> Should not forward player_media_status.player_is_playing = False player_media_status.player_is_paused = True - entity.new_media_status(player_media_status) - entity.media_pause() - grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + media_status_cb(player_media_status) + await common.async_media_pause(hass, entity_id) + grp_media = mz_mock.get_multizone_mediacontroller(str(FakeGroupUUID)) assert not grp_media.pause.called assert chromecast.media_controller.pause.called # Player is in unknown state, group is playing -> Should forward to group player_media_status.player_state = "UNKNOWN" - entity.new_media_status(player_media_status) - entity.media_stop() - grp_media = entity.mz_mgr.get_multizone_mediacontroller(str(FakeGroupUUID)) + media_status_cb(player_media_status) + await common.async_media_stop(hass, entity_id) + grp_media = mz_mock.get_multizone_mediacontroller(str(FakeGroupUUID)) assert grp_media.stop.called assert not chromecast.media_controller.stop.called # Verify play_media is not forwarded - entity.play_media(None, None) + await common.async_play_media(hass, "music", "best.mp3", entity_id) assert not grp_media.play_media.called assert chromecast.media_controller.play_media.called @@ -552,27 +948,28 @@ async def test_group_media_control(hass: HomeAssistantType): async def test_failed_cast_on_idle(hass, caplog): """Test no warning when unless player went idle with reason "ERROR".""" info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = False media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media" not in caplog.text media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "Other" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media" not in caplog.text media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media http://example.com:8123/tts.mp3." in caplog.text @@ -586,13 +983,14 @@ async def test_failed_cast_other_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert "Failed to cast media http://example.com:8123/tts.mp3." in caplog.text @@ -608,13 +1006,14 @@ async def test_failed_cast_internal_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.local:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert ( "Failed to cast media http://example.local:8123/tts.mp3 from internal_url" in caplog.text @@ -635,13 +1034,14 @@ async def test_failed_cast_external_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.com:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert ( "Failed to cast media http://example.com:8123/tts.mp3 from external_url" in caplog.text @@ -658,13 +1058,14 @@ async def test_failed_cast_tts_base_url(hass, caplog): ) info = get_fake_chromecast_info() - chromecast, entity = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) + _, _, media_status_cb = get_status_callbacks(chromecast) media_status = MagicMock(images=None) media_status.player_is_idle = True media_status.idle_reason = "ERROR" media_status.content_id = "http://example.local:8123/tts.mp3" - entity.new_media_status(media_status) + media_status_cb(media_status) assert ( "Failed to cast media http://example.local:8123/tts.mp3 from tts.base_url" in caplog.text @@ -675,7 +1076,7 @@ async def test_disconnect_on_stop(hass: HomeAssistantType): """Test cast device disconnects socket on stop.""" info = get_fake_chromecast_info() - chromecast, _ = await async_setup_media_player_cast(hass, info) + chromecast = await async_setup_media_player_cast(hass, info) hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) await hass.async_block_till_done()