
Added subsonic server config for salt auth logic See merge request sublime-music/sublime-music!47
204 lines
5.2 KiB
Python
204 lines
5.2 KiB
Python
from pathlib import Path
|
|
from time import sleep
|
|
|
|
import pytest
|
|
|
|
from sublime_music.adapters import (
|
|
AdapterManager,
|
|
ConfigurationStore,
|
|
Result,
|
|
SearchResult,
|
|
)
|
|
from sublime_music.adapters.filesystem import FilesystemAdapter
|
|
from sublime_music.adapters.subsonic import api_objects as SubsonicAPI, SubsonicAdapter
|
|
from sublime_music.config import AppConfiguration, ProviderConfiguration
|
|
|
|
|
|
@pytest.fixture
|
|
def adapter_manager(tmp_path: Path):
|
|
ConfigurationStore.MOCK = True
|
|
subsonic_config_store = ConfigurationStore(
|
|
server_address="https://subsonic.example.com",
|
|
username="test",
|
|
verify_cert=True,
|
|
salt_auth=False,
|
|
)
|
|
subsonic_config_store.set_secret("password", "testpass")
|
|
|
|
config = AppConfiguration(
|
|
providers={
|
|
"1": ProviderConfiguration(
|
|
id="1",
|
|
name="foo",
|
|
ground_truth_adapter_type=SubsonicAdapter,
|
|
ground_truth_adapter_config=subsonic_config_store,
|
|
caching_adapter_type=FilesystemAdapter,
|
|
caching_adapter_config=ConfigurationStore(),
|
|
)
|
|
},
|
|
current_provider_id="1",
|
|
cache_location=tmp_path,
|
|
)
|
|
AdapterManager.reset(config, lambda *a: None)
|
|
yield
|
|
AdapterManager.shutdown()
|
|
|
|
|
|
def test_result_immediate():
|
|
result = Result(42)
|
|
assert result.data_is_available
|
|
assert result.result() == 42
|
|
|
|
|
|
def test_result_immediate_callback():
|
|
callback_called = True
|
|
|
|
def check_done_callback(f: Result):
|
|
nonlocal callback_called
|
|
assert f.result() == 42
|
|
callback_called = True
|
|
|
|
result = Result(42)
|
|
result.add_done_callback(check_done_callback)
|
|
assert callback_called
|
|
|
|
|
|
def test_result_future():
|
|
def resolve_later() -> int:
|
|
sleep(0.1)
|
|
return 42
|
|
|
|
result = Result(resolve_later)
|
|
assert not result.data_is_available
|
|
assert result.result() == 42
|
|
assert result.data_is_available
|
|
|
|
|
|
def test_result_future_callback():
|
|
def resolve_later() -> int:
|
|
sleep(0.1)
|
|
return 42
|
|
|
|
check_done = False
|
|
|
|
def check_done_callback(f: Result):
|
|
nonlocal check_done
|
|
assert result.data_is_available
|
|
assert f.result() == 42
|
|
check_done = True
|
|
|
|
result = Result(resolve_later)
|
|
result.add_done_callback(check_done_callback)
|
|
|
|
# Should take much less than 1 seconds to complete. If the assertion fails, then the
|
|
# check_done_callback failed.
|
|
t = 0
|
|
while not check_done:
|
|
assert t < 1
|
|
t += 0.1
|
|
sleep(0.1)
|
|
|
|
|
|
def test_default_value():
|
|
def resolve_fail() -> int:
|
|
sleep(0.1)
|
|
raise Exception()
|
|
|
|
result = Result(resolve_fail, default_value=42)
|
|
assert not result.data_is_available
|
|
assert result.result() == 42
|
|
assert result.data_is_available
|
|
|
|
|
|
def test_cancel():
|
|
def resolve_later() -> int:
|
|
sleep(0.1)
|
|
return 42
|
|
|
|
cancel_called = False
|
|
|
|
def on_cancel():
|
|
nonlocal cancel_called
|
|
cancel_called = True
|
|
|
|
result = Result(resolve_later, on_cancel=on_cancel)
|
|
result.cancel()
|
|
assert cancel_called
|
|
assert not result.data_is_available
|
|
with pytest.raises(Exception):
|
|
result.result()
|
|
|
|
|
|
def test_get_song_details(adapter_manager: AdapterManager):
|
|
# song = AdapterManager.get_song_details("1")
|
|
# print(song)
|
|
# assert 0
|
|
# TODO (#180)
|
|
pass
|
|
|
|
|
|
def test_search_result_sort():
|
|
search_results1 = SearchResult(query="foo")
|
|
search_results1.add_results(
|
|
"artists",
|
|
[
|
|
# boo != foo so low match rate
|
|
SubsonicAPI.ArtistAndArtistInfo(id=str(i), name=f"boo{i}")
|
|
for i in range(30)
|
|
],
|
|
)
|
|
|
|
search_results2 = SearchResult(query="foo")
|
|
search_results1.add_results(
|
|
"artists",
|
|
[
|
|
# foo == foo, so high match rate
|
|
SubsonicAPI.ArtistAndArtistInfo(id=str(i), name=f"foo{i}")
|
|
for i in range(30)
|
|
],
|
|
)
|
|
|
|
# After unioning, the high match rate ones should be first, and only the top 20
|
|
# should be included.
|
|
search_results1.update(search_results2)
|
|
assert [a.name for a in search_results1.artists] == [f"foo{i}" for i in range(20)]
|
|
|
|
|
|
def test_search_result_update():
|
|
search_results1 = SearchResult(query="foo")
|
|
search_results1.add_results(
|
|
"artists",
|
|
[
|
|
SubsonicAPI.ArtistAndArtistInfo(id="1", name="foo"),
|
|
SubsonicAPI.ArtistAndArtistInfo(id="2", name="another foo"),
|
|
],
|
|
)
|
|
|
|
search_results2 = SearchResult(query="foo")
|
|
search_results2.add_results(
|
|
"artists",
|
|
[SubsonicAPI.ArtistAndArtistInfo(id="3", name="foo2")],
|
|
)
|
|
|
|
search_results1.update(search_results2)
|
|
assert [a.name for a in search_results1.artists] == ["foo", "another foo", "foo2"]
|
|
|
|
|
|
def test_search(adapter_manager: AdapterManager):
|
|
# TODO (#180)
|
|
return
|
|
results = []
|
|
|
|
# TODO (#180) ingest data
|
|
|
|
def search_callback(result: SearchResult):
|
|
results.append((result.artists, result.albums, result.songs, result.playlists))
|
|
|
|
AdapterManager.search("ohea", search_callback=search_callback).result()
|
|
|
|
# TODO (#180) test getting results from the server and updating using that
|
|
while len(results) < 1:
|
|
sleep(0.1)
|
|
|
|
assert len(results) == 1
|