update travis build

so we always test on the latest.
This commit is contained in:
Hellowlol 2020-04-16 23:51:18 +02:00
parent 37b4c8729d
commit 34c506107f
4 changed files with 125 additions and 97 deletions

View file

@ -56,7 +56,7 @@ jobs:
- stage: test - stage: test
python: 3.6 python: 3.6
env: env:
- PLEX_CONTAINER_TAG=1.10.1.4602-f54242b6b - PLEX_CONTAINER_TAG=latest
- TEST_ACCOUNT_ONCE=1 - TEST_ACCOUNT_ONCE=1
- stage: test - stage: test
python: 3.6 python: 3.6

View file

@ -19,54 +19,73 @@ except ImportError:
from mock import patch, MagicMock, mock_open from mock import patch, MagicMock, mock_open
SERVER_BASEURL = plexapi.CONFIG.get('auth.server_baseurl') SERVER_BASEURL = plexapi.CONFIG.get("auth.server_baseurl")
MYPLEX_USERNAME = plexapi.CONFIG.get('auth.myplex_username') MYPLEX_USERNAME = plexapi.CONFIG.get("auth.myplex_username")
MYPLEX_PASSWORD = plexapi.CONFIG.get('auth.myplex_password') 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(1999, 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}$"
AUDIOCHANNELS = {2, 6} AUDIOCHANNELS = {2, 6}
AUDIOLAYOUTS = {'5.1', '5.1(side)', 'stereo'} AUDIOLAYOUTS = {"5.1", "5.1(side)", "stereo"}
CODECS = {'aac', 'ac3', 'dca', 'h264', 'mp3', 'mpeg4'} CODECS = {"aac", "ac3", "dca", "h264", "mp3", "mpeg4"}
CONTAINERS = {'avi', 'mp4', 'mkv'} CONTAINERS = {"avi", "mp4", "mkv"}
CONTENTRATINGS = {'TV-14', 'TV-MA', 'G', 'NR', 'Not Rated'} CONTENTRATINGS = {"TV-14", "TV-MA", "G", "NR", "Not Rated"}
FRAMERATES = {'24p', 'PAL', 'NTSC'} FRAMERATES = {"24p", "PAL", "NTSC"}
PROFILES = {'advanced simple', 'main', 'constrained baseline'} PROFILES = {"advanced simple", "main", "constrained baseline"}
RESOLUTIONS = {'sd', '480', '576', '720', '1080'} RESOLUTIONS = {"sd", "480", "576", "720", "1080"}
ENTITLEMENTS = {'ios', 'roku', 'android', 'xbox_one', 'xbox_360', 'windows', 'windows_phone'} ENTITLEMENTS = {
"ios",
"roku",
"android",
"xbox_one",
"xbox_360",
"windows",
"windows_phone",
}
TEST_AUTHENTICATED = 'authenticated' TEST_AUTHENTICATED = "authenticated"
TEST_ANONYMOUSLY = 'anonymously' TEST_ANONYMOUSLY = "anonymously"
ANON_PARAM = pytest.param(TEST_ANONYMOUSLY, marks=pytest.mark.anonymous) ANON_PARAM = pytest.param(TEST_ANONYMOUSLY, marks=pytest.mark.anonymous)
AUTH_PARAM = pytest.param(TEST_AUTHENTICATED, marks=pytest.mark.authenticated) AUTH_PARAM = pytest.param(TEST_AUTHENTICATED, marks=pytest.mark.authenticated)
def pytest_addoption(parser): 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): def pytest_generate_tests(metafunc):
if 'plex' in metafunc.fixturenames: if "plex" in metafunc.fixturenames:
if 'account' in metafunc.fixturenames or TEST_AUTHENTICATED in metafunc.definition.keywords: if (
metafunc.parametrize('plex', [AUTH_PARAM], indirect=True) "account" in metafunc.fixturenames
or TEST_AUTHENTICATED in metafunc.definition.keywords
):
metafunc.parametrize("plex", [AUTH_PARAM], indirect=True)
else: else:
metafunc.parametrize('plex', [ANON_PARAM, AUTH_PARAM], indirect=True) metafunc.parametrize("plex", [ANON_PARAM, AUTH_PARAM], indirect=True)
elif 'account' in metafunc.fixturenames: elif "account" in metafunc.fixturenames:
metafunc.parametrize('account', [AUTH_PARAM], indirect=True) metafunc.parametrize("account", [AUTH_PARAM], indirect=True)
def pytest_runtest_setup(item): def pytest_runtest_setup(item):
if 'client' in item.keywords and not item.config.getvalue('client'): if "client" in item.keywords and not item.config.getvalue("client"):
return pytest.skip('Need --client option to run.') return pytest.skip("Need --client option to run.")
if TEST_AUTHENTICATED in item.keywords and not (MYPLEX_USERNAME and MYPLEX_PASSWORD): if TEST_AUTHENTICATED in item.keywords and not (
return pytest.skip('You have to specify MYPLEX_USERNAME and MYPLEX_PASSWORD to run authenticated tests') 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: 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 ' return pytest.skip(
'MYPLEX_PASSWORD') "Anonymous tests should be ran on unclaimed server, without providing MYPLEX_USERNAME and "
"MYPLEX_PASSWORD"
)
# --------------------------------- # ---------------------------------
@ -78,41 +97,50 @@ def get_account():
return MyPlexAccount() return MyPlexAccount()
@pytest.fixture(scope='session') @pytest.fixture(scope="session")
def account(): def account():
assert MYPLEX_USERNAME, 'Required MYPLEX_USERNAME not specified.' assert MYPLEX_USERNAME, "Required MYPLEX_USERNAME not specified."
assert MYPLEX_PASSWORD, 'Required MYPLEX_PASSWORD not specified.' assert MYPLEX_PASSWORD, "Required MYPLEX_PASSWORD not specified."
return get_account() return get_account()
@pytest.fixture(scope='session') @pytest.fixture(scope="session")
def account_once(account): def account_once(account):
if environ.get('TEST_ACCOUNT_ONCE') != '1' and environ.get('CI') == 'true': 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') pytest.skip("Do not forget to test this by providing TEST_ACCOUNT_ONCE=1")
return account return account
@pytest.fixture(scope='session') @pytest.fixture(scope="session")
def account_plexpass(account): def account_plexpass(account):
if not account.subscriptionActive: 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 return account
@pytest.fixture(scope='session') @pytest.fixture(scope="session")
def account_synctarget(account_plexpass): def account_synctarget(account_plexpass):
assert 'sync-target' in plexapi.X_PLEX_PROVIDES, 'You have to set env var ' \ assert "sync-target" in plexapi.X_PLEX_PROVIDES, (
'PLEXAPI_HEADER_PROVIDES=sync-target,controller' "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 "sync-target" in plexapi.BASE_HEADERS["X-Plex-Provides"]
assert '11.4.1' == plexapi.X_PLEX_PLATFORM_VERSION, 'You have to set env var PLEXAPI_HEADER_PLATFORM_VERSION=11.4.1' assert (
assert 'iPhone' == plexapi.X_PLEX_DEVICE, 'You have to set env var PLEXAPI_HEADER_DEVICE=iPhone' "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 return account_plexpass
@pytest.fixture(scope='session') @pytest.fixture(scope="session")
def plex(request): def plex(request):
assert SERVER_BASEURL, 'Required SERVER_BASEURL not specified.' assert SERVER_BASEURL, "Required SERVER_BASEURL not specified."
session = requests.Session() session = requests.Session()
if request.param == TEST_AUTHENTICATED: if request.param == TEST_AUTHENTICATED:
token = get_account().authenticationToken token = get_account().authenticationToken
@ -159,122 +187,130 @@ def client(request, plex):
@pytest.fixture() @pytest.fixture()
def tvshows(plex): def tvshows(plex):
return plex.library.section('TV Shows') return plex.library.section("TV Shows")
@pytest.fixture() @pytest.fixture()
def movies(plex): def movies(plex):
return plex.library.section('Movies') return plex.library.section("Movies")
@pytest.fixture() @pytest.fixture()
def music(plex): def music(plex):
return plex.library.section('Music') return plex.library.section("Music")
@pytest.fixture() @pytest.fixture()
def photos(plex): def photos(plex):
return plex.library.section('Photos') return plex.library.section("Photos")
@pytest.fixture() @pytest.fixture()
def movie(movies): def movie(movies):
return movies.get('Elephants Dream') return movies.get("Elephants Dream")
@pytest.fixture() @pytest.fixture()
def collection(plex, movie): def collection(plex):
try: try:
return plex.library.section('Movies').collection()[0] return plex.library.section("Movies").collection()[0]
except IndexError: except IndexError:
movie = plex.library.section("Movies").get("Elephants Dream")
movie.addCollection(["marvel"]) movie.addCollection(["marvel"])
n = plex.library.section('Movies').reload() n = plex.library.section("Movies").reload()
return n.collection()[0] return n.collection()[0]
@pytest.fixture() @pytest.fixture()
def artist(music): def artist(music):
return music.get('Infinite State') return music.get("Infinite State")
@pytest.fixture() @pytest.fixture()
def album(artist): def album(artist):
return artist.album('Unmastered Impulses') return artist.album("Unmastered Impulses")
@pytest.fixture() @pytest.fixture()
def track(album): def track(album):
return album.track('Holy Moment') return album.track("Holy Moment")
@pytest.fixture() @pytest.fixture()
def show(tvshows): def show(tvshows):
return tvshows.get('Game of Thrones') return tvshows.get("Game of Thrones")
@pytest.fixture() @pytest.fixture()
def episode(show): def episode(show):
return show.get('Winter Is Coming') return show.get("Winter Is Coming")
@pytest.fixture() @pytest.fixture()
def photoalbum(photos): def photoalbum(photos):
try: try:
return photos.get('Cats') return photos.get("Cats")
except Exception: except Exception:
return photos.get('photo_album1') return photos.get("photo_album1")
@pytest.fixture() @pytest.fixture()
def subtitle(): def subtitle():
mopen = mock_open() mopen = mock_open()
with patch('__main__.open', mopen): with patch("__main__.open", mopen):
with open('subtitle.srt', 'w') as handler: with open("subtitle.srt", "w") as handler:
handler.write('test') handler.write("test")
return handler return handler
@pytest.fixture() @pytest.fixture()
def shared_username(account): def shared_username(account):
username = environ.get('SHARED_USERNAME', 'PKKid') username = environ.get("SHARED_USERNAME", "PKKid")
for user in account.users(): for user in account.users():
if user.title.lower() == username.lower(): if user.title.lower() == username.lower():
return username return username
elif (user.username and user.email and user.id and username.lower() in elif (
(user.username.lower(), user.email.lower(), str(user.id))): user.username
and user.email
and user.id
and username.lower()
in (user.username.lower(), user.email.lower(), str(user.id))
):
return username 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() @pytest.fixture()
def monkeydownload(request, monkeypatch): 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 yield
monkeypatch.undo() monkeypatch.undo()
def callable_http_patch(): def callable_http_patch():
"""This intented to stop some http requests inside some tests.""" """This intented to stop some http requests inside some tests."""
return patch('plexapi.server.requests.sessions.Session.send', return patch(
return_value=MagicMock(status_code=200, "plexapi.server.requests.sessions.Session.send",
text='<xml><child></child></xml>')) return_value=MagicMock(status_code=200, text="<xml><child></child></xml>"),
)
@pytest.fixture() @pytest.fixture()
def empty_response(mocker): 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 return response
@pytest.fixture() @pytest.fixture()
def patched_http_call(mocker): def patched_http_call(mocker):
"""This will stop any http calls inside any test.""" """This will stop any http calls inside any test."""
return mocker.patch('plexapi.server.requests.sessions.Session.send', return mocker.patch(
return_value=MagicMock(status_code=200, "plexapi.server.requests.sessions.Session.send",
text='<xml><child></child></xml>') 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 return float(value) >= gte
def is_metadata(key, prefix='/library/metadata/', contains='', suffix=''): def is_metadata(key, prefix="/library/metadata/", contains="", suffix=""):
try: try:
assert key.startswith(prefix) assert key.startswith(prefix)
assert contains in key assert contains in key
@ -303,11 +339,11 @@ def is_metadata(key, prefix='/library/metadata/', contains='', suffix=''):
def is_part(key): def is_part(key):
return is_metadata(key, prefix='/library/parts/') return is_metadata(key, prefix="/library/parts/")
def is_section(key): def is_section(key):
return is_metadata(key, prefix='/library/sections/') return is_metadata(key, prefix="/library/sections/")
def is_string(value, gte=1): def is_string(value, gte=1):
@ -315,7 +351,7 @@ def is_string(value, gte=1):
def is_thumb(key): 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): 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) time.sleep(delay)
ready = condition_function(*args, **kwargs) 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 return ready

View file

@ -132,24 +132,12 @@ def test_server_history(plex, movie):
movie.markUnwatched() movie.markUnwatched()
@pytest.mark.anonymously
def test_server_Server_query(plex): def test_server_Server_query(plex):
assert plex.query('/') assert plex.query('/')
with pytest.raises(NotFound): with pytest.raises(NotFound):
assert plex.query('/asdf/1234/asdf', headers={'random_headers': '1234'}) 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): def test_server_Server_session(account):
# Mock Sesstion # Mock Sesstion
class MySession(Session): class MySession(Session):

View file

@ -97,6 +97,7 @@ def test_video_Episode_subtitlestreams(episode):
def test_video_Movie_upload_select_remove_subtitle(movie, subtitle): def test_video_Movie_upload_select_remove_subtitle(movie, subtitle):
filepath = os.path.realpath(subtitle.name) filepath = os.path.realpath(subtitle.name)
movie.uploadSubtitles(filepath) movie.uploadSubtitles(filepath)
movie.reload() movie.reload()
subtitles = [sub.title for sub in movie.subtitleStreams()] subtitles = [sub.title for sub in movie.subtitleStreams()]