"""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