core/tests/components/plex/mock_classes.py

613 lines
16 KiB
Python

"""Mock classes used in tests."""
from functools import lru_cache
from aiohttp.helpers import reify
from plexapi.exceptions import NotFound
from homeassistant.components.plex.const import (
CONF_SERVER,
CONF_SERVER_IDENTIFIER,
PLEX_SERVER_CONFIG,
)
from homeassistant.const import CONF_URL
from .const import DEFAULT_DATA, MOCK_SERVERS, MOCK_USERS
GDM_SERVER_PAYLOAD = [
{
"data": {
"Content-Type": "plex/media-server",
"Name": "plextest",
"Port": "32400",
"Resource-Identifier": "1234567890123456789012345678901234567890",
"Updated-At": "157762684800",
"Version": "1.0",
},
"from": ("1.2.3.4", 32414),
}
]
GDM_CLIENT_PAYLOAD = [
{
"data": {
"Content-Type": "plex/media-player",
"Device-Class": "stb",
"Name": "plexamp",
"Port": "36000",
"Product": "Plexamp",
"Protocol": "plex",
"Protocol-Capabilities": "timeline,playback,playqueues,playqueues-creation",
"Protocol-Version": "1",
"Resource-Identifier": "client-2",
"Version": "1.1.0",
},
"from": ("1.2.3.10", 32412),
},
{
"data": {
"Content-Type": "plex/media-player",
"Device-Class": "pc",
"Name": "Chrome",
"Port": "32400",
"Product": "Plex Web",
"Protocol": "plex",
"Protocol-Capabilities": "timeline,playback,navigation,mirror,playqueues",
"Protocol-Version": "3",
"Resource-Identifier": "client-1",
"Version": "4.40.1",
},
"from": ("1.2.3.4", 32412),
},
{
"data": {
"Content-Type": "plex/media-player",
"Device-Class": "mobile",
"Name": "SHIELD Android TV",
"Port": "32500",
"Product": "Plex for Android (TV)",
"Protocol": "plex",
"Protocol-Capabilities": "timeline,playback,navigation,mirror,playqueues,provider-playback",
"Protocol-Version": "1",
"Resource-Identifier": "client-999",
"Updated-At": "1597686153",
"Version": "8.5.0.19697",
},
"from": ("1.2.3.11", 32412),
},
]
class MockGDM:
"""Mock a GDM instance."""
def __init__(self, disabled=False):
"""Initialize the object."""
self.entries = []
self.disabled = disabled
def scan(self, scan_for_clients=False):
"""Mock the scan call."""
if self.disabled:
return
if scan_for_clients:
self.entries = GDM_CLIENT_PAYLOAD
else:
self.entries = GDM_SERVER_PAYLOAD
class MockResource:
"""Mock a PlexAccount resource."""
def __init__(self, index, kind="server"):
"""Initialize the object."""
if kind == "server":
self.name = MOCK_SERVERS[index][CONF_SERVER]
self.clientIdentifier = MOCK_SERVERS[index][ # pylint: disable=invalid-name
CONF_SERVER_IDENTIFIER
]
self.provides = ["server"]
self.device = MockPlexServer(index)
else:
self.name = f"plex.tv Resource Player {index+10}"
self.clientIdentifier = f"client-{index+10}"
self.provides = ["player"]
self.device = MockPlexClient(
baseurl=f"http://192.168.0.1{index}:32500", index=index + 10
)
self.presence = index == 0
self.publicAddressMatches = True
def connect(self, timeout):
"""Mock the resource connect method."""
return self.device
class MockPlexAccount:
"""Mock a PlexAccount instance."""
def __init__(self, servers=1, players=3):
"""Initialize the object."""
self._resources = []
for index in range(servers):
self._resources.append(MockResource(index))
for index in range(players):
self._resources.append(MockResource(index, kind="player"))
def resource(self, name):
"""Mock the PlexAccount resource lookup method."""
return [x for x in self._resources if x.name == name][0]
def resources(self):
"""Mock the PlexAccount resources listing method."""
return self._resources
def sonos_speaker(self, speaker_name):
"""Mock the PlexAccount Sonos lookup method."""
return MockPlexSonosClient(speaker_name)
class MockPlexSystemAccount:
"""Mock a PlexSystemAccount instance."""
def __init__(self, index):
"""Initialize the object."""
# Start accountIDs at 1 to set proper owner.
self.name = list(MOCK_USERS)[index]
self.accountID = index + 1
class MockPlexServer:
"""Mock a PlexServer instance."""
def __init__(
self,
index=0,
config_entry=None,
num_users=len(MOCK_USERS),
session_type="video",
):
"""Initialize the object."""
if config_entry:
self._data = config_entry.data
else:
self._data = DEFAULT_DATA
self._baseurl = self._data[PLEX_SERVER_CONFIG][CONF_URL]
self.friendlyName = self._data[CONF_SERVER]
self.machineIdentifier = self._data[CONF_SERVER_IDENTIFIER]
self._systemAccounts = list(map(MockPlexSystemAccount, range(num_users)))
self._clients = []
self._session = None
self._sessions = []
self.set_clients(num_users)
self.set_sessions(num_users, session_type)
self._cache = {}
def set_clients(self, num_clients):
"""Set up mock PlexClients for this PlexServer."""
self._clients = [
MockPlexClient(baseurl=self._baseurl, index=x) for x in range(num_clients)
]
def set_sessions(self, num_sessions, session_type):
"""Set up mock PlexSessions for this PlexServer."""
self._sessions = [
MockPlexSession(self._clients[x], mediatype=session_type, index=x)
for x in range(num_sessions)
]
def clear_clients(self):
"""Clear all active PlexClients."""
self._clients = []
def clear_sessions(self):
"""Clear all active PlexSessions."""
self._sessions = []
def clients(self):
"""Mock the clients method."""
return self._clients
def createToken(self):
"""Mock the createToken method."""
return "temporary_token"
def sessions(self):
"""Mock the sessions method."""
return self._sessions
def systemAccounts(self):
"""Mock the systemAccounts lookup method."""
return self._systemAccounts
def url(self, path, includeToken=False):
"""Mock method to generate a server URL."""
return f"{self._baseurl}{path}"
@property
def accounts(self):
"""Mock the accounts property."""
return set(MOCK_USERS)
@property
def version(self):
"""Mock version of PlexServer."""
return "1.0"
@reify
def library(self):
"""Mock library object of PlexServer."""
return MockPlexLibrary(self)
def playlist(self, playlist):
"""Mock the playlist lookup method."""
return MockPlexMediaItem(playlist, mediatype="playlist")
@lru_cache()
def playlists(self):
"""Mock the playlists lookup method with a lazy init."""
return [
MockPlexPlaylist(
self.library.section("Movies").all()
+ self.library.section("TV Shows").all()
),
MockPlexPlaylist(self.library.section("Music").all()),
]
def fetchItem(self, item):
"""Mock the fetchItem method."""
for section in self.library.sections():
result = section.fetchItem(item)
if result:
return result
class MockPlexClient:
"""Mock a PlexClient instance."""
def __init__(self, server=None, baseurl=None, token=None, index=0):
"""Initialize the object."""
self.machineIdentifier = f"client-{index+1}"
self._baseurl = baseurl
self._index = index
def url(self, key):
"""Mock the url method."""
return f"{self._baseurl}{key}"
@property
def device(self):
"""Mock the device attribute."""
return "DEVICE"
@property
def platform(self):
"""Mock the platform attribute."""
return "PLATFORM"
@property
def product(self):
"""Mock the product attribute."""
if self._index == 1:
return "Plex Web"
return "PRODUCT"
@property
def protocolCapabilities(self):
"""Mock the protocolCapabilities attribute."""
return ["playback"]
@property
def state(self):
"""Mock the state attribute."""
return "playing"
@property
def title(self):
"""Mock the title attribute."""
return "TITLE"
@property
def version(self):
"""Mock the version attribute."""
return "1.0"
def proxyThroughServer(self, value=True, server=None):
"""Mock the proxyThroughServer method."""
pass
def playMedia(self, item):
"""Mock the playMedia method."""
pass
class MockPlexSession:
"""Mock a PlexServer.sessions() instance."""
def __init__(self, player, mediatype, index=0):
"""Initialize the object."""
self.TYPE = mediatype
self.usernames = [list(MOCK_USERS)[index]]
self.players = [player]
self._section = MockPlexLibrarySection("Movies")
@property
def duration(self):
"""Mock the duration attribute."""
return 10000000
@property
def librarySectionID(self):
"""Mock the librarySectionID attribute."""
return 1
@property
def ratingKey(self):
"""Mock the ratingKey attribute."""
return 123
def section(self):
"""Mock the section method."""
return self._section
@property
def summary(self):
"""Mock the summary attribute."""
return "SUMMARY"
@property
def thumbUrl(self):
"""Mock the thumbUrl attribute."""
return "http://1.2.3.4/thumb"
@property
def title(self):
"""Mock the title attribute."""
return "TITLE"
@property
def type(self):
"""Mock the type attribute."""
return "movie"
@property
def viewOffset(self):
"""Mock the viewOffset attribute."""
return 0
@property
def year(self):
"""Mock the year attribute."""
return 2020
class MockPlexLibrary:
"""Mock a Plex Library instance."""
def __init__(self, plex_server):
"""Initialize the object."""
self._plex_server = plex_server
self._sections = {}
for kind in ["Movies", "Music", "TV Shows", "Photos"]:
self._sections[kind] = MockPlexLibrarySection(kind)
def section(self, title):
"""Mock the LibrarySection lookup."""
section = self._sections.get(title)
if section:
return section
raise NotFound
def sections(self):
"""Return all available sections."""
return self._sections.values()
def sectionByID(self, section_id):
"""Mock the sectionByID lookup."""
return [x for x in self.sections() if x.key == section_id][0]
def onDeck(self):
"""Mock an empty On Deck folder."""
return []
def recentlyAdded(self):
"""Mock an empty Recently Added folder."""
return []
class MockPlexLibrarySection:
"""Mock a Plex LibrarySection instance."""
def __init__(self, library):
"""Initialize the object."""
self.title = library
if library == "Music":
self._item = MockPlexArtist("Artist")
elif library == "TV Shows":
self._item = MockPlexShow("TV Show")
else:
self._item = MockPlexMediaItem(library[:-1])
def get(self, query):
"""Mock the get lookup method."""
if self._item.title == query:
return self._item
raise NotFound
def all(self):
"""Mock the all method."""
return [self._item]
def fetchItem(self, ratingKey):
"""Return a specific item."""
for item in self.all():
if item.ratingKey == ratingKey:
return item
if item._children:
for child in item._children:
if child.ratingKey == ratingKey:
return child
def onDeck(self):
"""Mock an empty On Deck folder."""
return []
def recentlyAdded(self):
"""Mock an empty Recently Added folder."""
return self.all()
@property
def type(self):
"""Mock the library type."""
if self.title == "Movies":
return "movie"
if self.title == "Music":
return "artist"
if self.title == "TV Shows":
return "show"
if self.title == "Photos":
return "photo"
@property
def TYPE(self):
"""Return the library type."""
return self.type
@property
def key(self):
"""Mock the key identifier property."""
return str(id(self.title))
def search(self, **kwargs):
"""Mock the LibrarySection search method."""
if kwargs.get("libtype") == "movie":
return self.all()
def update(self):
"""Mock the update call."""
pass
class MockPlexMediaItem:
"""Mock a Plex Media instance."""
def __init__(self, title, mediatype="video", year=2020):
"""Initialize the object."""
self.title = str(title)
self.type = mediatype
self.thumbUrl = "http://1.2.3.4/thumb.png"
self.year = year
self._children = []
def __iter__(self):
"""Provide iterator."""
yield from self._children
@property
def ratingKey(self):
"""Mock the ratingKey property."""
return id(self.title)
class MockPlexPlaylist(MockPlexMediaItem):
"""Mock a Plex Playlist instance."""
def __init__(self, items):
"""Initialize the object."""
super().__init__(f"Playlist ({len(items)} Items)", "playlist")
for item in items:
self._children.append(item)
class MockPlexShow(MockPlexMediaItem):
"""Mock a Plex Show instance."""
def __init__(self, show):
"""Initialize the object."""
super().__init__(show, "show")
for index in range(1, 5):
self._children.append(MockPlexSeason(index))
def season(self, season):
"""Mock the season lookup method."""
return [x for x in self._children if x.title == f"Season {season}"][0]
class MockPlexSeason(MockPlexMediaItem):
"""Mock a Plex Season instance."""
def __init__(self, season):
"""Initialize the object."""
super().__init__(f"Season {season}", "season")
for index in range(1, 10):
self._children.append(MockPlexMediaItem(f"Episode {index}", "episode"))
def episode(self, episode):
"""Mock the episode lookup method."""
return self._children[episode - 1]
class MockPlexAlbum(MockPlexMediaItem):
"""Mock a Plex Album instance."""
def __init__(self, album):
"""Initialize the object."""
super().__init__(album, "album")
for index in range(1, 10):
self._children.append(MockPlexMediaTrack(index))
def track(self, track):
"""Mock the track lookup method."""
try:
return [x for x in self._children if x.title == track][0]
except IndexError:
raise NotFound
def tracks(self):
"""Mock the tracks lookup method."""
return self._children
class MockPlexArtist(MockPlexMediaItem):
"""Mock a Plex Artist instance."""
def __init__(self, artist):
"""Initialize the object."""
super().__init__(artist, "artist")
self._album = MockPlexAlbum("Album")
def album(self, album):
"""Mock the album lookup method."""
return self._album
def get(self, track):
"""Mock the track lookup method."""
return self._album.track(track)
class MockPlexMediaTrack(MockPlexMediaItem):
"""Mock a Plex Track instance."""
def __init__(self, index=1):
"""Initialize the object."""
super().__init__(f"Track {index}", "track")
self.index = index
class MockPlexSonosClient:
"""Mock a PlexSonosClient instance."""
def __init__(self, name):
"""Initialize the object."""
self.name = name
def playMedia(self, item):
"""Mock the playMedia method."""
pass