mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-10 06:04:15 +00:00
update travis build
so we always test on the latest.
This commit is contained in:
parent
37b4c8729d
commit
34c506107f
4 changed files with 125 additions and 97 deletions
|
@ -56,7 +56,7 @@ jobs:
|
|||
- stage: test
|
||||
python: 3.6
|
||||
env:
|
||||
- PLEX_CONTAINER_TAG=1.10.1.4602-f54242b6b
|
||||
- PLEX_CONTAINER_TAG=latest
|
||||
- TEST_ACCOUNT_ONCE=1
|
||||
- stage: test
|
||||
python: 3.6
|
||||
|
|
|
@ -19,54 +19,73 @@ except ImportError:
|
|||
from mock import patch, MagicMock, mock_open
|
||||
|
||||
|
||||
SERVER_BASEURL = plexapi.CONFIG.get('auth.server_baseurl')
|
||||
MYPLEX_USERNAME = plexapi.CONFIG.get('auth.myplex_username')
|
||||
MYPLEX_PASSWORD = plexapi.CONFIG.get('auth.myplex_password')
|
||||
CLIENT_BASEURL = plexapi.CONFIG.get('auth.client_baseurl')
|
||||
CLIENT_TOKEN = plexapi.CONFIG.get('auth.client_token')
|
||||
SERVER_BASEURL = plexapi.CONFIG.get("auth.server_baseurl")
|
||||
MYPLEX_USERNAME = plexapi.CONFIG.get("auth.myplex_username")
|
||||
MYPLEX_PASSWORD = plexapi.CONFIG.get("auth.myplex_password")
|
||||
CLIENT_BASEURL = plexapi.CONFIG.get("auth.client_baseurl")
|
||||
CLIENT_TOKEN = plexapi.CONFIG.get("auth.client_token")
|
||||
|
||||
MIN_DATETIME = datetime(1999, 1, 1)
|
||||
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_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}$"
|
||||
|
||||
AUDIOCHANNELS = {2, 6}
|
||||
AUDIOLAYOUTS = {'5.1', '5.1(side)', 'stereo'}
|
||||
CODECS = {'aac', 'ac3', 'dca', 'h264', 'mp3', 'mpeg4'}
|
||||
CONTAINERS = {'avi', 'mp4', 'mkv'}
|
||||
CONTENTRATINGS = {'TV-14', 'TV-MA', 'G', 'NR', 'Not Rated'}
|
||||
FRAMERATES = {'24p', 'PAL', 'NTSC'}
|
||||
PROFILES = {'advanced simple', 'main', 'constrained baseline'}
|
||||
RESOLUTIONS = {'sd', '480', '576', '720', '1080'}
|
||||
ENTITLEMENTS = {'ios', 'roku', 'android', 'xbox_one', 'xbox_360', 'windows', 'windows_phone'}
|
||||
AUDIOLAYOUTS = {"5.1", "5.1(side)", "stereo"}
|
||||
CODECS = {"aac", "ac3", "dca", "h264", "mp3", "mpeg4"}
|
||||
CONTAINERS = {"avi", "mp4", "mkv"}
|
||||
CONTENTRATINGS = {"TV-14", "TV-MA", "G", "NR", "Not Rated"}
|
||||
FRAMERATES = {"24p", "PAL", "NTSC"}
|
||||
PROFILES = {"advanced simple", "main", "constrained baseline"}
|
||||
RESOLUTIONS = {"sd", "480", "576", "720", "1080"}
|
||||
ENTITLEMENTS = {
|
||||
"ios",
|
||||
"roku",
|
||||
"android",
|
||||
"xbox_one",
|
||||
"xbox_360",
|
||||
"windows",
|
||||
"windows_phone",
|
||||
}
|
||||
|
||||
TEST_AUTHENTICATED = 'authenticated'
|
||||
TEST_ANONYMOUSLY = 'anonymously'
|
||||
TEST_AUTHENTICATED = "authenticated"
|
||||
TEST_ANONYMOUSLY = "anonymously"
|
||||
ANON_PARAM = pytest.param(TEST_ANONYMOUSLY, marks=pytest.mark.anonymous)
|
||||
AUTH_PARAM = pytest.param(TEST_AUTHENTICATED, marks=pytest.mark.authenticated)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption('--client', action='store_true', default=False, help='Run client tests.')
|
||||
parser.addoption(
|
||||
"--client", action="store_true", default=False, help="Run client tests."
|
||||
)
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if 'plex' in metafunc.fixturenames:
|
||||
if 'account' in metafunc.fixturenames or TEST_AUTHENTICATED in metafunc.definition.keywords:
|
||||
metafunc.parametrize('plex', [AUTH_PARAM], indirect=True)
|
||||
if "plex" in metafunc.fixturenames:
|
||||
if (
|
||||
"account" in metafunc.fixturenames
|
||||
or TEST_AUTHENTICATED in metafunc.definition.keywords
|
||||
):
|
||||
metafunc.parametrize("plex", [AUTH_PARAM], indirect=True)
|
||||
else:
|
||||
metafunc.parametrize('plex', [ANON_PARAM, AUTH_PARAM], indirect=True)
|
||||
elif 'account' in metafunc.fixturenames:
|
||||
metafunc.parametrize('account', [AUTH_PARAM], indirect=True)
|
||||
metafunc.parametrize("plex", [ANON_PARAM, AUTH_PARAM], indirect=True)
|
||||
elif "account" in metafunc.fixturenames:
|
||||
metafunc.parametrize("account", [AUTH_PARAM], indirect=True)
|
||||
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
if 'client' in item.keywords and not item.config.getvalue('client'):
|
||||
return pytest.skip('Need --client option to run.')
|
||||
if TEST_AUTHENTICATED in item.keywords and not (MYPLEX_USERNAME and MYPLEX_PASSWORD):
|
||||
return pytest.skip('You have to specify MYPLEX_USERNAME and MYPLEX_PASSWORD to run authenticated tests')
|
||||
if "client" in item.keywords and not item.config.getvalue("client"):
|
||||
return pytest.skip("Need --client option to run.")
|
||||
if TEST_AUTHENTICATED in item.keywords and not (
|
||||
MYPLEX_USERNAME and MYPLEX_PASSWORD
|
||||
):
|
||||
return pytest.skip(
|
||||
"You have to specify MYPLEX_USERNAME and MYPLEX_PASSWORD to run authenticated tests"
|
||||
)
|
||||
if TEST_ANONYMOUSLY in item.keywords and MYPLEX_USERNAME and MYPLEX_PASSWORD:
|
||||
return pytest.skip('Anonymous tests should be ran on unclaimed server, without providing MYPLEX_USERNAME and '
|
||||
'MYPLEX_PASSWORD')
|
||||
return pytest.skip(
|
||||
"Anonymous tests should be ran on unclaimed server, without providing MYPLEX_USERNAME and "
|
||||
"MYPLEX_PASSWORD"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------
|
||||
|
@ -78,41 +97,50 @@ def get_account():
|
|||
return MyPlexAccount()
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope="session")
|
||||
def account():
|
||||
assert MYPLEX_USERNAME, 'Required MYPLEX_USERNAME not specified.'
|
||||
assert MYPLEX_PASSWORD, 'Required MYPLEX_PASSWORD not specified.'
|
||||
assert MYPLEX_USERNAME, "Required MYPLEX_USERNAME not specified."
|
||||
assert MYPLEX_PASSWORD, "Required MYPLEX_PASSWORD not specified."
|
||||
return get_account()
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope="session")
|
||||
def account_once(account):
|
||||
if environ.get('TEST_ACCOUNT_ONCE') != '1' and environ.get('CI') == 'true':
|
||||
pytest.skip('Do not forget to test this by providing TEST_ACCOUNT_ONCE=1')
|
||||
if environ.get("TEST_ACCOUNT_ONCE") != "1" and environ.get("CI") == "true":
|
||||
pytest.skip("Do not forget to test this by providing TEST_ACCOUNT_ONCE=1")
|
||||
return account
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope="session")
|
||||
def account_plexpass(account):
|
||||
if not account.subscriptionActive:
|
||||
pytest.skip('PlexPass subscription is not active, unable to test sync-stuff, be careful!')
|
||||
pytest.skip(
|
||||
"PlexPass subscription is not active, unable to test sync-stuff, be careful!"
|
||||
)
|
||||
return account
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope="session")
|
||||
def account_synctarget(account_plexpass):
|
||||
assert 'sync-target' in plexapi.X_PLEX_PROVIDES, 'You have to set env var ' \
|
||||
'PLEXAPI_HEADER_PROVIDES=sync-target,controller'
|
||||
assert 'sync-target' in plexapi.BASE_HEADERS['X-Plex-Provides']
|
||||
assert 'iOS' == plexapi.X_PLEX_PLATFORM, 'You have to set env var PLEXAPI_HEADER_PLATFORM=iOS'
|
||||
assert '11.4.1' == plexapi.X_PLEX_PLATFORM_VERSION, 'You have to set env var PLEXAPI_HEADER_PLATFORM_VERSION=11.4.1'
|
||||
assert 'iPhone' == plexapi.X_PLEX_DEVICE, 'You have to set env var PLEXAPI_HEADER_DEVICE=iPhone'
|
||||
assert "sync-target" in plexapi.X_PLEX_PROVIDES, (
|
||||
"You have to set env var " "PLEXAPI_HEADER_PROVIDES=sync-target,controller"
|
||||
)
|
||||
assert "sync-target" in plexapi.BASE_HEADERS["X-Plex-Provides"]
|
||||
assert (
|
||||
"iOS" == plexapi.X_PLEX_PLATFORM
|
||||
), "You have to set env var PLEXAPI_HEADER_PLATFORM=iOS"
|
||||
assert (
|
||||
"11.4.1" == plexapi.X_PLEX_PLATFORM_VERSION
|
||||
), "You have to set env var PLEXAPI_HEADER_PLATFORM_VERSION=11.4.1"
|
||||
assert (
|
||||
"iPhone" == plexapi.X_PLEX_DEVICE
|
||||
), "You have to set env var PLEXAPI_HEADER_DEVICE=iPhone"
|
||||
return account_plexpass
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
@pytest.fixture(scope="session")
|
||||
def plex(request):
|
||||
assert SERVER_BASEURL, 'Required SERVER_BASEURL not specified.'
|
||||
assert SERVER_BASEURL, "Required SERVER_BASEURL not specified."
|
||||
session = requests.Session()
|
||||
if request.param == TEST_AUTHENTICATED:
|
||||
token = get_account().authenticationToken
|
||||
|
@ -159,122 +187,130 @@ def client(request, plex):
|
|||
|
||||
@pytest.fixture()
|
||||
def tvshows(plex):
|
||||
return plex.library.section('TV Shows')
|
||||
return plex.library.section("TV Shows")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def movies(plex):
|
||||
return plex.library.section('Movies')
|
||||
return plex.library.section("Movies")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def music(plex):
|
||||
return plex.library.section('Music')
|
||||
return plex.library.section("Music")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def photos(plex):
|
||||
return plex.library.section('Photos')
|
||||
return plex.library.section("Photos")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def movie(movies):
|
||||
return movies.get('Elephants Dream')
|
||||
return movies.get("Elephants Dream")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def collection(plex, movie):
|
||||
|
||||
def collection(plex):
|
||||
try:
|
||||
return plex.library.section('Movies').collection()[0]
|
||||
return plex.library.section("Movies").collection()[0]
|
||||
except IndexError:
|
||||
movie = plex.library.section("Movies").get("Elephants Dream")
|
||||
movie.addCollection(["marvel"])
|
||||
|
||||
n = plex.library.section('Movies').reload()
|
||||
n = plex.library.section("Movies").reload()
|
||||
return n.collection()[0]
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def artist(music):
|
||||
return music.get('Infinite State')
|
||||
return music.get("Infinite State")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def album(artist):
|
||||
return artist.album('Unmastered Impulses')
|
||||
return artist.album("Unmastered Impulses")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def track(album):
|
||||
return album.track('Holy Moment')
|
||||
return album.track("Holy Moment")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def show(tvshows):
|
||||
return tvshows.get('Game of Thrones')
|
||||
return tvshows.get("Game of Thrones")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def episode(show):
|
||||
return show.get('Winter Is Coming')
|
||||
return show.get("Winter Is Coming")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def photoalbum(photos):
|
||||
try:
|
||||
return photos.get('Cats')
|
||||
return photos.get("Cats")
|
||||
except Exception:
|
||||
return photos.get('photo_album1')
|
||||
return photos.get("photo_album1")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def subtitle():
|
||||
mopen = mock_open()
|
||||
with patch('__main__.open', mopen):
|
||||
with open('subtitle.srt', 'w') as handler:
|
||||
handler.write('test')
|
||||
with patch("__main__.open", mopen):
|
||||
with open("subtitle.srt", "w") as handler:
|
||||
handler.write("test")
|
||||
return handler
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def shared_username(account):
|
||||
username = environ.get('SHARED_USERNAME', 'PKKid')
|
||||
username = environ.get("SHARED_USERNAME", "PKKid")
|
||||
for user in account.users():
|
||||
if user.title.lower() == username.lower():
|
||||
return username
|
||||
elif (user.username and user.email and user.id and username.lower() in
|
||||
(user.username.lower(), user.email.lower(), str(user.id))):
|
||||
elif (
|
||||
user.username
|
||||
and user.email
|
||||
and user.id
|
||||
and username.lower()
|
||||
in (user.username.lower(), user.email.lower(), str(user.id))
|
||||
):
|
||||
return username
|
||||
pytest.skip('Shared user %s wasn`t found in your MyPlex account' % username)
|
||||
pytest.skip("Shared user %s wasn`t found in your MyPlex account" % username)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def monkeydownload(request, monkeypatch):
|
||||
monkeypatch.setattr('plexapi.utils.download', partial(plexapi.utils.download, mocked=True))
|
||||
monkeypatch.setattr(
|
||||
"plexapi.utils.download", partial(plexapi.utils.download, mocked=True)
|
||||
)
|
||||
yield
|
||||
monkeypatch.undo()
|
||||
|
||||
|
||||
def callable_http_patch():
|
||||
"""This intented to stop some http requests inside some tests."""
|
||||
return patch('plexapi.server.requests.sessions.Session.send',
|
||||
return_value=MagicMock(status_code=200,
|
||||
text='<xml><child></child></xml>'))
|
||||
return patch(
|
||||
"plexapi.server.requests.sessions.Session.send",
|
||||
return_value=MagicMock(status_code=200, text="<xml><child></child></xml>"),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def empty_response(mocker):
|
||||
response = mocker.MagicMock(status_code=200, text='<xml><child></child></xml>')
|
||||
response = mocker.MagicMock(status_code=200, text="<xml><child></child></xml>")
|
||||
return response
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def patched_http_call(mocker):
|
||||
"""This will stop any http calls inside any test."""
|
||||
return mocker.patch('plexapi.server.requests.sessions.Session.send',
|
||||
return_value=MagicMock(status_code=200,
|
||||
text='<xml><child></child></xml>')
|
||||
)
|
||||
return mocker.patch(
|
||||
"plexapi.server.requests.sessions.Session.send",
|
||||
return_value=MagicMock(status_code=200, text="<xml><child></child></xml>"),
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------
|
||||
|
@ -292,7 +328,7 @@ def is_float(value, gte=1.0):
|
|||
return float(value) >= gte
|
||||
|
||||
|
||||
def is_metadata(key, prefix='/library/metadata/', contains='', suffix=''):
|
||||
def is_metadata(key, prefix="/library/metadata/", contains="", suffix=""):
|
||||
try:
|
||||
assert key.startswith(prefix)
|
||||
assert contains in key
|
||||
|
@ -303,11 +339,11 @@ def is_metadata(key, prefix='/library/metadata/', contains='', suffix=''):
|
|||
|
||||
|
||||
def is_part(key):
|
||||
return is_metadata(key, prefix='/library/parts/')
|
||||
return is_metadata(key, prefix="/library/parts/")
|
||||
|
||||
|
||||
def is_section(key):
|
||||
return is_metadata(key, prefix='/library/sections/')
|
||||
return is_metadata(key, prefix="/library/sections/")
|
||||
|
||||
|
||||
def is_string(value, gte=1):
|
||||
|
@ -315,7 +351,7 @@ def is_string(value, gte=1):
|
|||
|
||||
|
||||
def is_thumb(key):
|
||||
return is_metadata(key, contains='/thumb/')
|
||||
return is_metadata(key, contains="/thumb/")
|
||||
|
||||
|
||||
def wait_until(condition_function, delay=0.25, timeout=1, *args, **kwargs):
|
||||
|
@ -327,6 +363,9 @@ def wait_until(condition_function, delay=0.25, timeout=1, *args, **kwargs):
|
|||
time.sleep(delay)
|
||||
ready = condition_function(*args, **kwargs)
|
||||
|
||||
assert ready, 'Wait timeout after %d retries, %.2f seconds' % (retries, time.time() - start)
|
||||
assert ready, "Wait timeout after %d retries, %.2f seconds" % (
|
||||
retries,
|
||||
time.time() - start,
|
||||
)
|
||||
|
||||
return ready
|
||||
|
|
|
@ -132,24 +132,12 @@ def test_server_history(plex, movie):
|
|||
movie.markUnwatched()
|
||||
|
||||
|
||||
@pytest.mark.anonymously
|
||||
def test_server_Server_query(plex):
|
||||
assert plex.query('/')
|
||||
with pytest.raises(NotFound):
|
||||
assert plex.query('/asdf/1234/asdf', headers={'random_headers': '1234'})
|
||||
|
||||
|
||||
@pytest.mark.authenticated
|
||||
def test_server_Server_query_authenticated(plex):
|
||||
assert plex.query('/')
|
||||
with pytest.raises(BadRequest):
|
||||
assert plex.query('/asdf/1234/asdf', headers={'random_headers': '1234'})
|
||||
with pytest.raises(BadRequest):
|
||||
# This is really requests.exceptions.HTTPError
|
||||
# 401 Client Error: Unauthorized for url
|
||||
PlexServer(utils.SERVER_BASEURL, '1234')
|
||||
|
||||
|
||||
def test_server_Server_session(account):
|
||||
# Mock Sesstion
|
||||
class MySession(Session):
|
||||
|
|
|
@ -97,6 +97,7 @@ def test_video_Episode_subtitlestreams(episode):
|
|||
def test_video_Movie_upload_select_remove_subtitle(movie, subtitle):
|
||||
|
||||
filepath = os.path.realpath(subtitle.name)
|
||||
|
||||
movie.uploadSubtitles(filepath)
|
||||
movie.reload()
|
||||
subtitles = [sub.title for sub in movie.subtitleStreams()]
|
||||
|
|
Loading…
Reference in a new issue