async def test_debouncer(hass, caplog): """Test debouncer decorator logic.""" entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=DEFAULT_OPTIONS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "homeassistant.components.plex.PlexWebsocket.listen" ): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier # First two updates are skipped async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() next_update = dt_util.utcnow() + timedelta(seconds=DEBOUNCE_TIMEOUT) async_fire_time_changed(hass, next_update) await hass.async_block_till_done() assert ( caplog.text.count(f"Throttling update of {mock_plex_server.friendlyName}") == 2 )
async def test_debouncer(self): """Test debouncer behavior.""" hass = self.hass entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=DEFAULT_OPTIONS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "homeassistant.components.plex.PlexWebsocket.listen"): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier with patch.object( mock_plex_server, "clients", return_value=[]), patch.object(mock_plex_server, "sessions", return_value=[]) as mock_update: # Called immediately async_dispatcher_send( hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() assert mock_update.call_count == 1 # Throttled async_dispatcher_send( hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() assert mock_update.call_count == 1 # Throttled async_dispatcher_send( hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() assert mock_update.call_count == 1 # Called from scheduler await self.advance(DEBOUNCE_TIMEOUT) await hass.async_block_till_done() assert mock_update.call_count == 2 # Throttled async_dispatcher_send( hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() assert mock_update.call_count == 2 # Called from scheduler await self.advance(DEBOUNCE_TIMEOUT) await hass.async_block_till_done() assert mock_update.call_count == 3
async def test_ignore_plex_web_client(hass): """Test option to ignore Plex Web clients.""" OPTIONS = copy.deepcopy(DEFAULT_OPTIONS) OPTIONS[MP_DOMAIN][CONF_IGNORE_PLEX_WEB_CLIENTS] = True entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=OPTIONS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "homeassistant.components.plex.PlexWebsocket.listen" ): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() sensor = hass.states.get("sensor.plex_plex_server_1") assert sensor.state == str(len(mock_plex_server.accounts)) media_players = hass.states.async_entity_ids("media_player") assert len(media_players) == int(sensor.state) - 1
async def trigger_plex_update(hass, server_id): """Update Plex by sending signal and jumping ahead by debounce timeout.""" async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() next_update = dt_util.utcnow() + timedelta(seconds=DEBOUNCE_TIMEOUT) async_fire_time_changed(hass, next_update) await hass.async_block_till_done()
async def test_option_flow_new_users_available(hass, caplog): """Test config options multiselect defaults when new Plex users are seen.""" OPTIONS_OWNER_ONLY = copy.deepcopy(DEFAULT_OPTIONS) OPTIONS_OWNER_ONLY[MP_DOMAIN][CONF_MONITORED_USERS] = { "Owner": { "enabled": True } } entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=OPTIONS_OWNER_ONLY, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "plexapi.myplex.MyPlexAccount", return_value=MockPlexAccount()), patch( "homeassistant.components.plex.PlexWebsocket.listen"): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier with patch("plexapi.myplex.MyPlexAccount", return_value=MockPlexAccount()): async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() monitored_users = hass.data[DOMAIN][SERVERS][ server_id].option_monitored_users new_users = [ x for x in mock_plex_server.accounts if x not in monitored_users ] assert len(monitored_users) == 1 assert len(new_users) == 2 sensor = hass.states.get("sensor.plex_plex_server_1") assert sensor.state == str(len(mock_plex_server.accounts)) result = await hass.config_entries.options.async_init( entry.entry_id, context={"source": "test"}, data=None) assert result["type"] == "form" assert result["step_id"] == "plex_mp_settings" multiselect_defaults = result["data_schema"].schema[ "monitored_users"].options assert "[Owner]" in multiselect_defaults["Owner"] for user in new_users: assert "[New]" in multiselect_defaults[user]
async def test_mark_sessions_idle(self): """Test marking media_players as idle when sessions end.""" hass = self.hass entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=DEFAULT_OPTIONS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "homeassistant.components.plex.PlexWebsocket.listen"): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() sensor = hass.states.get("sensor.plex_plex_server_1") assert sensor.state == str(len(mock_plex_server.accounts)) mock_plex_server.clear_clients() mock_plex_server.clear_sessions() await self.advance(DEBOUNCE_TIMEOUT) async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() sensor = hass.states.get("sensor.plex_plex_server_1") assert sensor.state == "0"
async def test_new_ignored_users_available(hass, caplog): """Test setting up when new users available on Plex server but are ignored.""" MONITORED_USERS = {"Owner": {"enabled": True}} OPTIONS_WITH_USERS = copy.deepcopy(DEFAULT_OPTIONS) OPTIONS_WITH_USERS[MP_DOMAIN][CONF_MONITORED_USERS] = MONITORED_USERS OPTIONS_WITH_USERS[MP_DOMAIN][CONF_IGNORE_NEW_SHARED_USERS] = True entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=OPTIONS_WITH_USERS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "plexapi.myplex.MyPlexAccount", return_value=MockPlexAccount()), patch( "homeassistant.components.plex.PlexWebsocket.listen"): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() monitored_users = hass.data[DOMAIN][SERVERS][ server_id].option_monitored_users ignored_users = [ x for x in mock_plex_server.accounts if x not in monitored_users ] assert len(monitored_users) == 1 assert len(ignored_users) == 2 for ignored_user in ignored_users: ignored_client = [ x.players[0] for x in mock_plex_server.sessions() if x.usernames[0] == ignored_user ][0] assert ( f"Ignoring {ignored_client.product} client owned by '{ignored_user}'" in caplog.text) sensor = hass.states.get("sensor.plex_plex_server_1") assert sensor.state == str(len(mock_plex_server.accounts))
async def test_new_users_available(hass): """Test setting up when new users available on Plex server.""" MONITORED_USERS = {"Owner": {"enabled": True}} OPTIONS_WITH_USERS = copy.deepcopy(DEFAULT_OPTIONS) OPTIONS_WITH_USERS[MP_DOMAIN][CONF_MONITORED_USERS] = MONITORED_USERS entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=OPTIONS_WITH_USERS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "plexapi.myplex.MyPlexAccount", return_value=MockPlexAccount()), patch( "homeassistant.components.plex.PlexWebsocket.listen"): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() monitored_users = hass.data[DOMAIN][SERVERS][ server_id].option_monitored_users ignored_users = [ x for x in monitored_users if not monitored_users[x]["enabled"] ] assert len(monitored_users) == 1 assert len(ignored_users) == 0 sensor = hass.states.get("sensor.plex_plex_server_1") assert sensor.state == str(len(mock_plex_server.accounts))
async def test_media_lookups(hass): """Test media lookups to Plex server.""" entry = MockConfigEntry( domain=DOMAIN, data=DEFAULT_DATA, options=DEFAULT_OPTIONS, unique_id=DEFAULT_DATA["server_id"], ) mock_plex_server = MockPlexServer(config_entry=entry) with patch("plexapi.server.PlexServer", return_value=mock_plex_server), patch( "homeassistant.components.plex.PlexWebsocket.listen" ): entry.add_to_hass(hass) assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() server_id = mock_plex_server.machineIdentifier loaded_server = hass.data[DOMAIN][SERVERS][server_id] # Plex Key searches async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id)) await hass.async_block_till_done() media_player_id = hass.states.async_entity_ids("media_player")[0] with patch("homeassistant.components.plex.PlexServer.create_playqueue"): assert await hass.services.async_call( MP_DOMAIN, SERVICE_PLAY_MEDIA, { ATTR_ENTITY_ID: media_player_id, ATTR_MEDIA_CONTENT_TYPE: DOMAIN, ATTR_MEDIA_CONTENT_ID: 123, }, True, ) with patch.object(MockPlexServer, "fetchItem", side_effect=NotFound): assert await hass.services.async_call( MP_DOMAIN, SERVICE_PLAY_MEDIA, { ATTR_ENTITY_ID: media_player_id, ATTR_MEDIA_CONTENT_TYPE: DOMAIN, ATTR_MEDIA_CONTENT_ID: 123, }, True, ) # TV show searches with patch.object(MockPlexLibrary, "section", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="Not a Library", show_name="A TV Show" ) is None ) with patch.object(MockPlexLibrarySection, "get", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", show_name="Not a TV Show" ) is None ) assert ( loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", episode_name="An Episode" ) is None ) assert loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", show_name="A TV Show" ) assert loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", show_name="A TV Show", season_number=2, ) assert loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", show_name="A TV Show", season_number=2, episode_number=3, ) with patch.object(MockPlexMediaItem, "season", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", show_name="A TV Show", season_number=2, ) is None ) with patch.object(MockPlexMediaItem, "episode", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_EPISODE, library_name="TV Shows", show_name="A TV Show", season_number=2, episode_number=1, ) is None ) # Music searches assert ( loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", album_name="An Album" ) is None ) assert loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist" ) assert loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", track_name="A Track", ) assert loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", album_name="An Album", ) with patch.object(MockPlexLibrarySection, "get", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="Not an Artist", album_name="An Album", ) is None ) with patch.object(MockPlexArtist, "album", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", album_name="Not an Album", ) is None ) with patch.object(MockPlexMediaItem, "track", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", album_name="An Album", track_name="Not a Track", ) is None ) with patch.object(MockPlexArtist, "get", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", track_name="Not a Track", ) is None ) assert loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", album_name="An Album", track_number=3, ) assert ( loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", album_name="An Album", track_number=30, ) is None ) assert loaded_server.lookup_media( MEDIA_TYPE_MUSIC, library_name="Music", artist_name="An Artist", album_name="An Album", track_name="A Track", ) # Playlist searches assert loaded_server.lookup_media(MEDIA_TYPE_PLAYLIST, playlist_name="A Playlist") assert loaded_server.lookup_media(MEDIA_TYPE_PLAYLIST) is None with patch.object(MockPlexServer, "playlist", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_PLAYLIST, playlist_name="Not a Playlist" ) is None ) # Movie searches assert loaded_server.lookup_media(MEDIA_TYPE_VIDEO, video_name="A Movie") is None assert loaded_server.lookup_media(MEDIA_TYPE_VIDEO, library_name="Movies") is None assert loaded_server.lookup_media( MEDIA_TYPE_VIDEO, library_name="Movies", video_name="A Movie" ) with patch.object(MockPlexLibrarySection, "get", side_effect=NotFound): assert ( loaded_server.lookup_media( MEDIA_TYPE_VIDEO, library_name="Movies", video_name="Not a Movie" ) is None )