Initial import: Music_Server, MusicFree, catalog-sync
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
import sqlite3
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from music_server.app import create_app
|
||||
from tests.support import auth_headers
|
||||
|
||||
|
||||
class MfDetailRouteTests(unittest.TestCase):
|
||||
def _prepare_catalog_db(self, db_path: Path) -> None:
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.executescript(
|
||||
"""
|
||||
create table catalog_playlists (
|
||||
playlist_id integer primary key,
|
||||
platform text not null,
|
||||
remote_playlist_id text not null,
|
||||
name text not null,
|
||||
description text,
|
||||
cover_url text,
|
||||
play_count integer not null,
|
||||
song_count integer not null,
|
||||
playable_song_count integer not null
|
||||
);
|
||||
|
||||
create table catalog_tracks (
|
||||
song_id integer primary key,
|
||||
platform text not null,
|
||||
remote_song_id text not null,
|
||||
name text not null,
|
||||
singers text,
|
||||
album text,
|
||||
cover_url text,
|
||||
duration_ms integer not null,
|
||||
source_meta text not null
|
||||
);
|
||||
|
||||
create table catalog_playlist_tracks (
|
||||
playlist_id integer not null,
|
||||
song_id integer not null,
|
||||
position integer not null,
|
||||
primary key (playlist_id, song_id)
|
||||
);
|
||||
|
||||
create table catalog_toplists (
|
||||
toplist_id text primary key,
|
||||
platform text not null,
|
||||
name text not null,
|
||||
description text,
|
||||
cover_url text,
|
||||
play_count integer not null,
|
||||
song_count integer not null,
|
||||
playable_song_count integer not null,
|
||||
group_name text not null
|
||||
);
|
||||
|
||||
create table catalog_toplist_tracks (
|
||||
toplist_id text not null,
|
||||
song_id integer not null,
|
||||
position integer not null,
|
||||
primary key (toplist_id, song_id)
|
||||
);
|
||||
|
||||
create table catalog_track_files (
|
||||
song_id integer not null,
|
||||
quality_label text not null,
|
||||
ext text not null,
|
||||
file_size_bytes integer,
|
||||
backend_type text not null,
|
||||
backend_name text not null,
|
||||
locator text not null,
|
||||
public_url text,
|
||||
status text not null,
|
||||
is_primary integer not null
|
||||
);
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
insert into catalog_playlists (
|
||||
playlist_id, platform, remote_playlist_id, name, description, cover_url, play_count, song_count, playable_song_count
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(1, "netease", "18165", "playlist-1", "desc", "https://img/p.jpg", 2000, 2, 2),
|
||||
)
|
||||
conn.executemany(
|
||||
"""
|
||||
insert into catalog_tracks (
|
||||
song_id, platform, remote_song_id, name, singers, album, cover_url, duration_ms, source_meta
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
[
|
||||
(
|
||||
3476,
|
||||
"netease",
|
||||
"65800",
|
||||
"song-3476",
|
||||
"artist-a",
|
||||
"album-a",
|
||||
"https://img/s-3476.jpg",
|
||||
220000,
|
||||
"{}",
|
||||
),
|
||||
(
|
||||
4001,
|
||||
"qq",
|
||||
"4001",
|
||||
"song-4001",
|
||||
"artist-b",
|
||||
"album-b",
|
||||
"https://img/s-4001.jpg",
|
||||
180000,
|
||||
"{}",
|
||||
),
|
||||
],
|
||||
)
|
||||
conn.executemany(
|
||||
"""
|
||||
insert into catalog_playlist_tracks (playlist_id, song_id, position)
|
||||
values (?, ?, ?)
|
||||
""",
|
||||
[(1, 3476, 1), (1, 4001, 2)],
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
insert into catalog_toplists (
|
||||
toplist_id, platform, name, description, cover_url, play_count, song_count, playable_song_count, group_name
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
"kuwo_top_16",
|
||||
"kuwo",
|
||||
"\u9177\u6211\u98d9\u5347\u699c",
|
||||
"desc",
|
||||
"https://img/t.jpg",
|
||||
1000,
|
||||
2,
|
||||
2,
|
||||
"\u9177\u6211",
|
||||
),
|
||||
)
|
||||
conn.executemany(
|
||||
"""
|
||||
insert into catalog_toplist_tracks (toplist_id, song_id, position)
|
||||
values (?, ?, ?)
|
||||
""",
|
||||
[("kuwo_top_16", 3476, 1), ("kuwo_top_16", 4001, 2)],
|
||||
)
|
||||
conn.executemany(
|
||||
"""
|
||||
insert into catalog_track_files (
|
||||
song_id, quality_label, ext, file_size_bytes, backend_type, backend_name, locator, public_url, status, is_primary
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
[
|
||||
(
|
||||
3476,
|
||||
"super",
|
||||
"flac",
|
||||
100,
|
||||
"object_storage",
|
||||
"cdn",
|
||||
"song-3476.flac",
|
||||
"https://cdn/song-3476.flac",
|
||||
"active",
|
||||
1,
|
||||
),
|
||||
(
|
||||
4001,
|
||||
"standard",
|
||||
"mp3",
|
||||
90,
|
||||
"object_storage",
|
||||
"cdn",
|
||||
"song-4001.mp3",
|
||||
"https://cdn/song-4001.mp3",
|
||||
"active",
|
||||
1,
|
||||
),
|
||||
],
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@contextmanager
|
||||
def _catalog_client(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
db_path = Path(tmpdir) / "catalog_read.db"
|
||||
player_db_path = Path(tmpdir) / "player.db"
|
||||
self._prepare_catalog_db(db_path)
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"PUBLIC_MUSIC_ACCESS_TOKEN": "dev-token",
|
||||
"CATALOG_DB_PATH": str(db_path),
|
||||
"PLAYER_DB_PATH": str(player_db_path),
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
yield TestClient(create_app()), player_db_path
|
||||
|
||||
def test_get_toplist_detail_returns_musicfree_shape(self):
|
||||
with self._catalog_client() as (client, player_db_path):
|
||||
response = client.get(
|
||||
"/mf/v1/toplists/kuwo_top_16",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertEqual("catalogsync:toplist:kuwo_top_16", payload["id"])
|
||||
self.assertEqual("catalogsync", payload["platform"])
|
||||
self.assertEqual("\u9177\u6211\u98d9\u5347\u699c", payload["title"])
|
||||
|
||||
def test_get_toplist_tracks_pagination(self):
|
||||
with self._catalog_client() as (client, player_db_path):
|
||||
first_page = client.get(
|
||||
"/mf/v1/toplists/kuwo_top_16/tracks?page=1&page_size=1",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
second_page = client.get(
|
||||
"/mf/v1/toplists/kuwo_top_16/tracks?page=2&page_size=1",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(200, first_page.status_code)
|
||||
self.assertFalse(first_page.json()["isEnd"])
|
||||
self.assertEqual("catalogsync:song:3476", first_page.json()["musicList"][0]["id"])
|
||||
|
||||
self.assertEqual(200, second_page.status_code)
|
||||
self.assertTrue(second_page.json()["isEnd"])
|
||||
self.assertEqual("catalogsync:song:4001", second_page.json()["musicList"][0]["id"])
|
||||
|
||||
def test_get_toplist_detail_returns_404_when_missing(self):
|
||||
with self._catalog_client() as (client, player_db_path):
|
||||
response = client.get(
|
||||
"/mf/v1/toplists/missing_toplist",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
def test_get_toplist_tracks_returns_404_when_missing(self):
|
||||
with self._catalog_client() as (client, player_db_path):
|
||||
response = client.get(
|
||||
"/mf/v1/toplists/missing_toplist/tracks?page=1&page_size=1",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
def test_get_toplist_routes_require_token(self):
|
||||
with self._catalog_client() as (client, _player_db_path):
|
||||
detail_response = client.get("/mf/v1/toplists/kuwo_top_16")
|
||||
tracks_response = client.get(
|
||||
"/mf/v1/toplists/kuwo_top_16/tracks?page=1&page_size=1"
|
||||
)
|
||||
|
||||
self.assertEqual(401, detail_response.status_code)
|
||||
self.assertEqual(401, tracks_response.status_code)
|
||||
|
||||
def test_legacy_playlist_tracks_and_toplists_routes_still_work(self):
|
||||
with self._catalog_client() as (client, player_db_path):
|
||||
playlist_tracks_response = client.get(
|
||||
"/mf/v1/playlists/1/tracks?page=1&page_size=20",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
toplists_response = client.get(
|
||||
"/mf/v1/toplists",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(200, playlist_tracks_response.status_code)
|
||||
playlist_payload = playlist_tracks_response.json()
|
||||
self.assertTrue(playlist_payload["musicList"])
|
||||
self.assertEqual("catalogsync:song:3476", playlist_payload["musicList"][0]["id"])
|
||||
|
||||
self.assertEqual(200, toplists_response.status_code)
|
||||
toplists_payload = toplists_response.json()
|
||||
self.assertEqual("\u9177\u6211", toplists_payload[0]["title"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user