Separate Plex/Sonos cross-integration tests (#45370)
parent
16843d9ec7
commit
1f66457a34
|
@ -70,8 +70,9 @@ def refresh_library(hass, service_call):
|
|||
|
||||
def get_plex_server(hass, plex_server_name=None):
|
||||
"""Retrieve a configured Plex server by name."""
|
||||
if DOMAIN not in hass.data:
|
||||
raise HomeAssistantError("Plex integration not configured")
|
||||
plex_servers = hass.data[DOMAIN][SERVERS].values()
|
||||
|
||||
if not plex_servers:
|
||||
raise HomeAssistantError("No Plex servers available")
|
||||
|
||||
|
@ -106,7 +107,7 @@ def lookup_plex_media(hass, content_type, content_id):
|
|||
plex_server_name = content.pop("plex_server", None)
|
||||
shuffle = content.pop("shuffle", 0)
|
||||
|
||||
plex_server = get_plex_server(hass, plex_server_name=plex_server_name)
|
||||
plex_server = get_plex_server(hass, plex_server_name)
|
||||
|
||||
media = plex_server.lookup_media(content_type, **content)
|
||||
if media is None:
|
||||
|
|
|
@ -254,6 +254,12 @@ def show_seasons_fixture():
|
|||
return load_fixture("plex/show_seasons.xml")
|
||||
|
||||
|
||||
@pytest.fixture(name="sonos_resources", scope="session")
|
||||
def sonos_resources_fixture():
|
||||
"""Load Sonos resources payload and return it."""
|
||||
return load_fixture("plex/sonos_resources.xml")
|
||||
|
||||
|
||||
@pytest.fixture(name="entry")
|
||||
def mock_config_entry():
|
||||
"""Return the default mocked config entry."""
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
"""Tests for various Plex services."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from plexapi.exceptions import NotFound
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.media_player.const import MEDIA_TYPE_MUSIC
|
||||
from homeassistant.components.plex.const import (
|
||||
CONF_SERVER,
|
||||
CONF_SERVER_IDENTIFIER,
|
||||
|
@ -9,6 +13,7 @@ from homeassistant.components.plex.const import (
|
|||
SERVICE_REFRESH_LIBRARY,
|
||||
SERVICE_SCAN_CLIENTS,
|
||||
)
|
||||
from homeassistant.components.plex.services import play_on_sonos
|
||||
from homeassistant.const import CONF_URL
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
|
@ -100,3 +105,76 @@ async def test_scan_clients(hass, mock_plex_server):
|
|||
SERVICE_SCAN_CLIENTS,
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
|
||||
async def test_sonos_play_media(
|
||||
hass,
|
||||
entry,
|
||||
setup_plex_server,
|
||||
requests_mock,
|
||||
empty_payload,
|
||||
playqueue_created,
|
||||
plextv_account,
|
||||
sonos_resources,
|
||||
):
|
||||
"""Test playback from a Sonos media_player.play_media call."""
|
||||
media_content_id = (
|
||||
'{"library_name": "Music", "artist_name": "Artist", "album_name": "Album"}'
|
||||
)
|
||||
sonos_speaker_name = "Zone A"
|
||||
|
||||
requests_mock.get("https://plex.tv/users/account", text=plextv_account)
|
||||
requests_mock.post("/playqueues", text=playqueue_created)
|
||||
playback_mock = requests_mock.get("/player/playback/playMedia", status_code=200)
|
||||
|
||||
# Test with no Plex integration available
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name)
|
||||
assert "Plex integration not configured" in str(excinfo.value)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.plex.PlexServer.connect", side_effect=NotFound
|
||||
):
|
||||
# Initialize Plex integration without setting up a server
|
||||
with pytest.raises(AssertionError):
|
||||
await setup_plex_server()
|
||||
|
||||
# Test with no Plex servers available
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name)
|
||||
assert "No Plex servers available" in str(excinfo.value)
|
||||
|
||||
# Complete setup of a Plex server
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
mock_plex_server = await setup_plex_server()
|
||||
|
||||
# Test with no speakers available
|
||||
requests_mock.get("https://sonos.plex.tv/resources", text=empty_payload)
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name)
|
||||
assert f"Sonos speaker '{sonos_speaker_name}' is not associated with" in str(
|
||||
excinfo.value
|
||||
)
|
||||
assert playback_mock.call_count == 0
|
||||
|
||||
# Test with speakers available
|
||||
requests_mock.get("https://sonos.plex.tv/resources", text=sonos_resources)
|
||||
with patch.object(mock_plex_server.account, "_sonos_cache_timestamp", 0):
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, media_content_id, sonos_speaker_name)
|
||||
assert playback_mock.call_count == 1
|
||||
|
||||
# Test with speakers available and media key payload
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, "100", sonos_speaker_name)
|
||||
assert playback_mock.call_count == 2
|
||||
|
||||
# Test with speakers available and Plex server specified
|
||||
content_id_with_server = '{"plex_server": "Plex Server 1", "library_name": "Music", "artist_name": "Artist", "album_name": "Album"}'
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, content_id_with_server, sonos_speaker_name)
|
||||
assert playback_mock.call_count == 3
|
||||
|
||||
# Test with speakers available but media not found
|
||||
content_id_bad_media = '{"library_name": "Music", "artist_name": "Not an Artist"}'
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
play_on_sonos(hass, MEDIA_TYPE_MUSIC, content_id_bad_media, sonos_speaker_name)
|
||||
assert "Plex media not found" in str(excinfo.value)
|
||||
assert playback_mock.call_count == 3
|
||||
|
|
|
@ -7,7 +7,7 @@ from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
|||
from homeassistant.components.sonos import DOMAIN
|
||||
from homeassistant.const import CONF_HOSTS
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(name="config_entry")
|
||||
|
@ -77,21 +77,3 @@ def speaker_info_fixture():
|
|||
"software_version": "49.2-64250",
|
||||
"mac_address": "00-11-22-33-44-55",
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(name="plex_empty_payload", scope="session")
|
||||
def plex_empty_payload_fixture():
|
||||
"""Load an empty payload and return it."""
|
||||
return load_fixture("plex/empty_payload.xml")
|
||||
|
||||
|
||||
@pytest.fixture(name="plextv_account", scope="session")
|
||||
def plextv_account_fixture():
|
||||
"""Load account info from plex.tv and return it."""
|
||||
return load_fixture("plex/plextv_account.xml")
|
||||
|
||||
|
||||
@pytest.fixture(name="plex_sonos_resources", scope="session")
|
||||
def plex_sonos_resources_fixture():
|
||||
"""Load Sonos resources payload and return it."""
|
||||
return load_fixture("plex/sonos_resources.xml")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""Tests for the Sonos Media Player platform."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from plexapi.myplex import MyPlexAccount
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.media_player.const import (
|
||||
|
@ -11,7 +10,7 @@ from homeassistant.components.media_player.const import (
|
|||
MEDIA_TYPE_MUSIC,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
)
|
||||
from homeassistant.components.plex.const import DOMAIN as PLEX_DOMAIN, SERVERS
|
||||
from homeassistant.components.plex.const import PLEX_URI_SCHEME
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
|
@ -22,99 +21,47 @@ async def test_plex_play_media(
|
|||
hass,
|
||||
config_entry,
|
||||
config,
|
||||
requests_mock,
|
||||
plextv_account,
|
||||
plex_empty_payload,
|
||||
plex_sonos_resources,
|
||||
):
|
||||
"""Test playing media via the Plex integration."""
|
||||
requests_mock.get("https://plex.tv/users/account", text=plextv_account)
|
||||
requests_mock.get("https://sonos.plex.tv/resources", text=plex_empty_payload)
|
||||
|
||||
class MockPlexServer:
|
||||
"""Mock a PlexServer instance."""
|
||||
|
||||
def __init__(self, has_media=False):
|
||||
self.account = MyPlexAccount(token="token")
|
||||
self.friendly_name = "plex"
|
||||
if has_media:
|
||||
self.media = "media"
|
||||
else:
|
||||
self.media = None
|
||||
|
||||
def create_playqueue(self, media, **kwargs):
|
||||
pass
|
||||
|
||||
def lookup_media(self, content_type, **kwargs):
|
||||
return self.media
|
||||
|
||||
await setup_platform(hass, config_entry, config)
|
||||
hass.data[PLEX_DOMAIN] = {SERVERS: {}}
|
||||
media_player = "media_player.zone_a"
|
||||
media_content_id = (
|
||||
'{"library_name": "Music", "artist_name": "Artist", "album_name": "Album"}'
|
||||
)
|
||||
|
||||
# Test Plex service call with media key
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
with patch(
|
||||
"homeassistant.components.sonos.media_player.play_on_sonos"
|
||||
) as mock_play:
|
||||
# Test successful Plex service call
|
||||
assert await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
{
|
||||
ATTR_ENTITY_ID: media_player,
|
||||
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC,
|
||||
ATTR_MEDIA_CONTENT_ID: "plex://5",
|
||||
ATTR_MEDIA_CONTENT_ID: f"{PLEX_URI_SCHEME}{media_content_id}",
|
||||
},
|
||||
True,
|
||||
blocking=True,
|
||||
)
|
||||
assert "No Plex servers available" in str(excinfo.value)
|
||||
|
||||
# Add a mocked Plex server with no media
|
||||
hass.data[PLEX_DOMAIN][SERVERS] = {"plex": MockPlexServer()}
|
||||
assert len(mock_play.mock_calls) == 1
|
||||
assert mock_play.mock_calls[0][1][1] == MEDIA_TYPE_MUSIC
|
||||
assert mock_play.mock_calls[0][1][2] == media_content_id
|
||||
assert mock_play.mock_calls[0][1][3] == "Zone A"
|
||||
|
||||
# Test Plex service call with dict
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
assert await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
{
|
||||
ATTR_ENTITY_ID: media_player,
|
||||
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC,
|
||||
ATTR_MEDIA_CONTENT_ID: 'plex://{"library_name": "Music", "artist_name": "Artist"}',
|
||||
},
|
||||
True,
|
||||
)
|
||||
assert "Plex media not found" in str(excinfo.value)
|
||||
# Test failed Plex service call
|
||||
mock_play.reset_mock()
|
||||
mock_play.side_effect = HomeAssistantError
|
||||
|
||||
# Add a mocked Plex server
|
||||
hass.data[PLEX_DOMAIN][SERVERS] = {"plex": MockPlexServer(has_media=True)}
|
||||
|
||||
# Test Plex service call with no Sonos speakers
|
||||
requests_mock.get("https://sonos.plex.tv/resources", text=plex_empty_payload)
|
||||
with pytest.raises(HomeAssistantError) as excinfo:
|
||||
assert await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
{
|
||||
ATTR_ENTITY_ID: media_player,
|
||||
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC,
|
||||
ATTR_MEDIA_CONTENT_ID: 'plex://{"library_name": "Music", "artist_name": "Artist"}',
|
||||
},
|
||||
True,
|
||||
)
|
||||
assert "Sonos speaker 'Zone A' is not associated with" in str(excinfo.value)
|
||||
|
||||
# Test successful Plex service call
|
||||
account = hass.data[PLEX_DOMAIN][SERVERS]["plex"].account
|
||||
requests_mock.get("https://sonos.plex.tv/resources", text=plex_sonos_resources)
|
||||
|
||||
with patch.object(account, "_sonos_cache_timestamp", 0), patch(
|
||||
"plexapi.sonos.PlexSonosClient.playMedia"
|
||||
):
|
||||
assert await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
{
|
||||
ATTR_ENTITY_ID: media_player,
|
||||
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC,
|
||||
ATTR_MEDIA_CONTENT_ID: 'plex://{"plex_server": "plex", "library_name": "Music", "artist_name": "Artist", "album_name": "Album"}',
|
||||
},
|
||||
True,
|
||||
)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
await hass.services.async_call(
|
||||
MP_DOMAIN,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
{
|
||||
ATTR_ENTITY_ID: media_player,
|
||||
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC,
|
||||
ATTR_MEDIA_CONTENT_ID: f"{PLEX_URI_SCHEME}{media_content_id}",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert mock_play.called
|
||||
|
|
Loading…
Reference in New Issue