Files
sublime-music/tests/adapter_tests/subsonic_adapter_tests.py
2020-05-08 11:30:23 -06:00

170 lines
5.1 KiB
Python

import json
import logging
import re
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any, Generator, Tuple
import pytest
from sublime.adapters.subsonic import (
api_objects as SubsonicAPI,
SubsonicAdapter,
)
MOCK_DATA_FILES = Path(__file__).parent.joinpath("mock_data")
@pytest.fixture
def adapter(tmp_path: Path):
adapter = SubsonicAdapter(
{
"server_address": "http://subsonic.example.com",
"username": "test",
"password": "testpass",
},
tmp_path,
)
adapter._is_mock = True
yield adapter
def mock_data_files(
request_name: str, mode: str = "r"
) -> Generator[Tuple[Path, Any], None, None]:
"""
Yields all of the files in the mock_data directory that start with ``request_name``.
"""
for file in MOCK_DATA_FILES.iterdir():
if file.name.split("-")[0] in request_name:
with open(file, mode) as f:
yield file, f.read()
def mock_json(**obj: Any) -> str:
return json.dumps(
{"subsonic-response": {"status": "ok", "version": "1.15.0", **obj}}
)
def camel_to_snake(name: str) -> str:
name = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", name).lower()
def test_request_making_methods(adapter: SubsonicAdapter):
expected = {
"u": "test",
"p": "testpass",
"c": "Sublime Music",
"f": "json",
"v": "1.15.0",
}
assert sorted(expected.items()) == sorted(adapter._get_params().items())
assert adapter._make_url("foo") == "http://subsonic.example.com/rest/foo.view"
def test_can_service_requests(adapter: SubsonicAdapter):
# Mock a connection error
adapter._set_mock_data(Exception())
assert adapter.can_service_requests is False
# Simulate some sort of ping error
for filename, data in mock_data_files("ping_failed"):
logging.info(filename)
logging.debug(data)
adapter._set_mock_data(data)
assert adapter.can_service_requests is False
# Simulate valid ping
adapter._set_mock_data(mock_json())
assert adapter.can_service_requests is True
def test_get_playlists(adapter: SubsonicAdapter):
expected = [
SubsonicAPI.Playlist(
id="2",
name="Test",
song_count=132,
duration=timedelta(seconds=33072),
created=datetime(2020, 3, 27, 5, 38, 45, 0, tzinfo=timezone.utc),
changed=datetime(2020, 4, 9, 16, 3, 26, 0, tzinfo=timezone.utc),
comment="Foo",
owner="foo",
public=True,
cover_art="pl-2",
),
SubsonicAPI.Playlist(
id="3",
name="Bar",
song_count=23,
duration=timedelta(seconds=847),
created=datetime(2020, 3, 27, 5, 39, 4, 0, tzinfo=timezone.utc),
changed=datetime(2020, 3, 27, 5, 45, 23, 0, tzinfo=timezone.utc),
comment="",
owner="foo",
public=False,
cover_art="pl-3",
),
]
for filename, data in mock_data_files("get_playlists"):
logging.info(filename)
logging.debug(data)
adapter._set_mock_data(data)
assert adapter.get_playlists() == expected
# When playlists is null, expect an empty list.
adapter._set_mock_data(mock_json())
assert adapter.get_playlists() == []
def test_get_playlist_details(adapter: SubsonicAdapter):
for filename, data in mock_data_files("get_playlist_details"):
logging.info(filename)
logging.debug(data)
adapter._set_mock_data(data)
playlist_details = adapter.get_playlist_details("2")
# Make sure that the song count is correct even if it's not provided.
# Old versions of Subsonic don't have these properties.
assert len(playlist_details.songs) == 2
assert playlist_details.duration == timedelta(seconds=470)
# Make sure that at least the first song got decoded properly.
assert playlist_details.songs[0] == SubsonicAPI.Song(
id="202",
parent="318",
title="What a Beautiful Name",
album="What a Beautiful Name - Single",
artist="Hillsong Worship",
track=1,
year=2016,
genre="Christian & Gospel",
cover_art="318",
size=8381640,
content_type="audio/mp4",
suffix="m4a",
transcoded_content_type="audio/mpeg",
transcoded_suffix="mp3",
duration=timedelta(seconds=238),
bit_rate=256,
path="/".join(
(
"Hillsong Worship",
"What a Beautiful Name - Single",
"01 What a Beautiful Name.m4a",
)
),
is_video=False,
play_count=20,
disc_number=1,
created=datetime(2020, 3, 27, 5, 17, 7, tzinfo=timezone.utc),
album_id="48",
artist_id="38",
type=SubsonicAPI.SublimeAPI.MediaType.MUSIC,
)