Started movinf client tests into Pytest framework

This commit is contained in:
Michael Shepanski 2017-05-12 23:25:57 -04:00
parent ef8eb94bc5
commit 650a88d638
7 changed files with 75 additions and 27 deletions

View file

@ -70,6 +70,10 @@ class PlexClient(PlexObject):
if connect and self._baseurl: if connect and self._baseurl:
self.connect(timeout=timeout) self.connect(timeout=timeout)
def _nextCommandId(self):
self._commandId += 0
return self._commandId
def connect(self, timeout=None): def connect(self, timeout=None):
""" Alias of reload as any subsequent requests to this client will be """ Alias of reload as any subsequent requests to this client will be
made directly to the device even if the object attributes were initially made directly to the device even if the object attributes were initially
@ -113,7 +117,7 @@ class PlexClient(PlexObject):
headers.update(kwargs) headers.update(kwargs)
return headers return headers
def proxyThroughServer(self, value=True): def proxyThroughServer(self, value=True, server=None):
""" Tells this PlexClient instance to proxy all future commands through the PlexServer. """ Tells this PlexClient instance to proxy all future commands through the PlexServer.
Useful if you do not wish to connect directly to the Client device itself. Useful if you do not wish to connect directly to the Client device itself.
@ -123,6 +127,8 @@ class PlexClient(PlexObject):
Raises: Raises:
:class:`~plexapi.exceptions.Unsupported`: Cannot use client proxy with unknown server. :class:`~plexapi.exceptions.Unsupported`: Cannot use client proxy with unknown server.
""" """
if server:
self._server = server
if value is True and not self._server: if value is True and not self._server:
raise Unsupported('Cannot use client proxy with unknown server.') raise Unsupported('Cannot use client proxy with unknown server.')
self._proxyThroughServer = value self._proxyThroughServer = value
@ -165,8 +171,7 @@ class PlexClient(PlexObject):
raise Unsupported('Client %s doesnt support %s controller.' % (self.title, controller)) raise Unsupported('Client %s doesnt support %s controller.' % (self.title, controller))
key = '/player/%s%s' % (command, utils.joinArgs(params)) key = '/player/%s%s' % (command, utils.joinArgs(params))
headers = {'X-Plex-Target-Client-Identifier': self.machineIdentifier} headers = {'X-Plex-Target-Client-Identifier': self.machineIdentifier}
self._commandId += 1 params['commandID'] = self._nextCommandId()
params['commandID'] = self._commandId
proxy = self._proxyThroughServer if proxy is None else proxy proxy = self._proxyThroughServer if proxy is None else proxy
if proxy: if proxy:
return self._server.query(key, headers=headers) return self._server.query(key, headers=headers)
@ -428,6 +433,8 @@ class PlexClient(PlexObject):
'port': server_url[-1], 'port': server_url[-1],
'offset': offset, 'offset': offset,
'key': media.key, 'key': media.key,
'token': self._server._token,
'commandID': self._nextCommandId(),
'containerKey': '/playQueues/%s?window=100&own=1' % playqueue.playQueueID, 'containerKey': '/playQueues/%s?window=100&own=1' % playqueue.playQueueID,
}, **params)) }, **params))

View file

@ -93,20 +93,17 @@ class MediaPart(PlexObject):
streams.append(cls(self._server, elem, self._initpath)) streams.append(cls(self._server, elem, self._initpath))
return streams return streams
@property
def videoStreams(self): def videoStreams(self):
""" Returns a list of :class:`~plexapi.media.VideoStream` objects in this MediaPart. """ """ Returns a list of :class:`~plexapi.media.VideoStream` objects in this MediaPart. """
return [s for s in self.streams if s.streamType == VideoStream.STREAMTYPE] return [stream for stream in self.streams if stream.streamType == VideoStream.STREAMTYPE]
@property
def audioStreams(self): def audioStreams(self):
""" Returns a list of :class:`~plexapi.media.AudioStream` objects in this MediaPart. """ """ Returns a list of :class:`~plexapi.media.AudioStream` objects in this MediaPart. """
return [s for s in self.streams if s.streamType == AudioStream.STREAMTYPE] return [stream for stream in self.streams if stream.streamType == AudioStream.STREAMTYPE]
@property
def subtitleStreams(self): def subtitleStreams(self):
""" Returns a list of :class:`~plexapi.media.SubtitleStream` objects in this MediaPart. """ """ Returns a list of :class:`~plexapi.media.SubtitleStream` objects in this MediaPart. """
return [s for s in self.streams if s.streamType == SubtitleStream.STREAMTYPE] return [stream for stream in self.streams if stream.streamType == SubtitleStream.STREAMTYPE]
class MediaPartStream(PlexObject): class MediaPartStream(PlexObject):

View file

@ -144,7 +144,15 @@ class Movie(Video, Playable):
""" This does not exist in plex xml response but is added to have a common """ This does not exist in plex xml response but is added to have a common
interface to get the location of the Movie/Show/Episode interface to get the location of the Movie/Show/Episode
""" """
return [p.file for p in self.iterParts() if p] return [part.file for part in self.iterParts() if part]
def subtitleStreams(self):
""" Returns a list of :class:`~plexapi.media.SubtitleStream` objects for all MediaParts. """
streams = []
for elem in self.media:
for part in elem.parts:
streams += part.subtitleStreams()
return streams
def _prettyfilename(self): def _prettyfilename(self):
# This is just for compat. # This is just for compat.

View file

@ -30,7 +30,7 @@ MYPLEX_PASSWORD = plexapi.CONFIG.get('auth.myplex_password')
CLIENT_BASEURL = plexapi.CONFIG.get('auth.client_baseurl') CLIENT_BASEURL = plexapi.CONFIG.get('auth.client_baseurl')
CLIENT_TOKEN = plexapi.CONFIG.get('auth.client_token') CLIENT_TOKEN = plexapi.CONFIG.get('auth.client_token')
MIN_DATETIME = datetime(2008, 1, 1) MIN_DATETIME = datetime(1999, 1, 1)
REGEX_EMAIL = r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)' REGEX_EMAIL = r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)'
REGEX_IPADDR = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' REGEX_IPADDR = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
@ -79,7 +79,7 @@ def plex2():
@pytest.fixture() @pytest.fixture()
def client(request): def client(request):
return PlexClient(baseurl=CLIENT_BASEURL, token=CLIENT_TOKEN) return PlexClient(plex(), baseurl=CLIENT_BASEURL, token=CLIENT_TOKEN)
@pytest.fixture() @pytest.fixture()

View file

@ -2,6 +2,18 @@
import pytest, time import pytest, time
def _check_capabilities(client, capabilities):
supported = client.protocolCapabilities
for capability in capabilities:
if capability not in supported:
pytest.skip('Client doesnt support %s capability.', capability)
def _check_proxy(plex, client, proxy):
if proxy:
client.proxyThroughServer(server=plex)
@pytest.mark.client @pytest.mark.client
def test_list_clients(account, plex): def test_list_clients(account, plex):
assert account.resources(), 'MyPlex is not listing any devlices.' assert account.resources(), 'MyPlex is not listing any devlices.'
@ -10,17 +22,10 @@ def test_list_clients(account, plex):
@pytest.mark.client @pytest.mark.client
def test_client_navigation_direct(plex, client, episode, artist): @pytest.mark.parametrize('proxy', [False, True])
_navigate(plex, client, episode, artist) def test_client_navigation(plex, client, episode, artist, proxy):
_check_capabilities(client, ['navigation'])
_check_proxy(plex, client, proxy)
@pytest.mark.client
def test_client_navigation_via_proxy(plex, client, episode, artist):
client.proxyThroughServer()
_navigate(plex, client, episode, artist)
def _navigate(plex, client, episode, artist):
# Browse around a bit.. # Browse around a bit..
client.moveDown(); time.sleep(0.5) client.moveDown(); time.sleep(0.5)
client.moveDown(); time.sleep(0.5) client.moveDown(); time.sleep(0.5)
@ -44,6 +49,36 @@ def _navigate(plex, client, episode, artist):
client.goBack(); time.sleep(5) client.goBack(); time.sleep(5)
@pytest.mark.client
@pytest.mark.parametrize('proxy', [False, True])
def test_video_playback(plex, client, movie, proxy):
_check_capabilities(client, ['playback'])
_check_proxy(plex, client, proxy)
try:
# Need a movie with subtitles
movie = plex.library.section('Movies').get('Moana').reload()
mtype = 'video'
subs = [stream for stream in movie.subtitleStreams() if stream.language == 'English']
# Basic play ability
print('Basic play ability')
client.playMedia(movie); time.sleep(5)
client.pause(mtype); time.sleep(2)
# Step forward, back, seek in time
print('Step forward, back, seek in time')
client.stepForward(mtype); time.sleep(5)
client.play(mtype); time.sleep(3)
client.stepBack(mtype); time.sleep(5)
client.play(mtype); time.sleep(3)
client.seekTo(10*60*1000); time.sleep(5)
# Enable subtitles
print('Enable subtitles')
client.setSubtitleStream(0, mtype); time.sleep(10)
client.setSubtitleStream(subs[0].id, mtype); time.sleep(10)
client.stop(mtype); time.sleep(1)
finally:
movie.markWatched()
@pytest.mark.client @pytest.mark.client
def _test_client_PlexClient__loadData(pms): def _test_client_PlexClient__loadData(pms):
pass pass

View file

@ -20,7 +20,7 @@ def test_server_attr(plex):
assert plex.platform in ('Linux', 'Windows') assert plex.platform in ('Linux', 'Windows')
assert len(plex.platformVersion) >= 5 assert len(plex.platformVersion) >= 5
assert plex._token == utils.SERVER_TOKEN assert plex._token == utils.SERVER_TOKEN
assert plex.transcoderActiveVideoSessions == 0 assert utils.is_int(plex.transcoderActiveVideoSessions, gte=0)
assert utils.is_datetime(plex.updatedAt) assert utils.is_datetime(plex.updatedAt)
assert len(plex.version) >= 5 assert len(plex.version) >= 5
@ -168,7 +168,7 @@ def test_server_client_not_found(plex):
def test_server_Server_sessions(plex): def test_server_Server_sessions(plex):
assert len(plex.sessions()) == 0 assert len(plex.sessions()) >= 0
@pytest.mark.client @pytest.mark.client

View file

@ -81,7 +81,8 @@ def test_video_Movie_attrs(movies):
assert movie.originallyAvailableAt.strftime('%Y-%m-%d') in ('2008-01-11', '2008-02-11') assert movie.originallyAvailableAt.strftime('%Y-%m-%d') in ('2008-01-11', '2008-02-11')
assert movie.player is None assert movie.player is None
assert movie.playlistItemID is None assert movie.playlistItemID is None
assert movie.primaryExtraKey is None if movie.primaryExtraKey:
assert utils.is_metadata(movie.primaryExtraKey)
assert [i.tag for i in movie.producers] == [] assert [i.tag for i in movie.producers] == []
assert float(movie.rating) >= 6.4 assert float(movie.rating) >= 6.4
assert movie.ratingImage == 'rottentomatoes://image.rating.ripe' assert movie.ratingImage == 'rottentomatoes://image.rating.ripe'
@ -460,7 +461,7 @@ def test_video_Episode_attrs(episode):
def test_video_Season(show): def test_video_Season(show):
seasons = show.seasons() seasons = show.seasons()
assert len(seasons) >= 1 assert len(seasons) >= 1
assert ['Season 1', 'Season 2'] == [s.title for s in seasons] assert ['Season 1', 'Season 2'] == [s.title for s in seasons[:2]]
assert show.season('Season 1') == seasons[0] assert show.season('Season 1') == seasons[0]