Initial import: Music_Server, MusicFree, catalog-sync
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import sqlite3
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from music_server.app import create_app
|
||||
from music_server.services.token_service import TokenService
|
||||
from tests.support import auth_headers, issue_access_token
|
||||
|
||||
|
||||
class AuthRouteTests(unittest.TestCase):
|
||||
def _prepare_catalog_db(self, db_path: Path) -> None:
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.execute(
|
||||
"""
|
||||
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.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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
[
|
||||
(101, "super", "flac", 100, "object_storage", "cdn", "101.flac", None, "active", 1),
|
||||
(101, "standard", "mp3", 80, "object_storage", "cdn", "101.mp3", None, "active", 0),
|
||||
(102, "standard", "mp3", 90, "object_storage", "cdn", "102.mp3", None, "inactive", 1),
|
||||
(103, "standard", "mp3", 90, "object_storage", "cdn", "103.mp3", None, "active", 1),
|
||||
],
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def test_token_status_active_returns_playable_song_count(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
player_db_path = Path(tmpdir) / "player.db"
|
||||
catalog_db_path = Path(tmpdir) / "catalog_read.db"
|
||||
self._prepare_catalog_db(catalog_db_path)
|
||||
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"PLAYER_DB_PATH": str(player_db_path),
|
||||
"CATALOG_DB_PATH": str(catalog_db_path),
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
client = TestClient(create_app())
|
||||
response = client.get(
|
||||
"/auth/v1/token-status",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertTrue(payload["valid"])
|
||||
self.assertEqual("active", payload["status"])
|
||||
self.assertEqual(2, payload["playableSongCount"])
|
||||
|
||||
def test_token_status_client_id_missing_uses_body_status_not_401(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
player_db_path = Path(tmpdir) / "player.db"
|
||||
catalog_db_path = Path(tmpdir) / "catalog_read.db"
|
||||
self._prepare_catalog_db(catalog_db_path)
|
||||
token = issue_access_token(player_db_path)
|
||||
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"PLAYER_DB_PATH": str(player_db_path),
|
||||
"CATALOG_DB_PATH": str(catalog_db_path),
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
client = TestClient(create_app())
|
||||
response = client.get(
|
||||
"/auth/v1/token-status",
|
||||
headers=auth_headers(
|
||||
player_db_path,
|
||||
token=token,
|
||||
include_client_id=False,
|
||||
),
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertFalse(payload["valid"])
|
||||
self.assertEqual("client_id_missing", payload["status"])
|
||||
self.assertIsNone(payload["playableSongCount"])
|
||||
|
||||
def test_token_status_rejects_missing_bearer(self):
|
||||
client = TestClient(create_app())
|
||||
response = client.get("/auth/v1/token-status")
|
||||
|
||||
self.assertEqual(401, response.status_code)
|
||||
|
||||
def test_token_status_allows_missing_bearer_when_auth_disabled(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
player_db_path = Path(tmpdir) / "player.db"
|
||||
catalog_db_path = Path(tmpdir) / "catalog_read.db"
|
||||
self._prepare_catalog_db(catalog_db_path)
|
||||
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"PLAYER_DB_PATH": str(player_db_path),
|
||||
"CATALOG_DB_PATH": str(catalog_db_path),
|
||||
"MUSIC_SERVER_DISABLE_AUTH": "1",
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
client = TestClient(create_app())
|
||||
response = client.get("/auth/v1/token-status")
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertTrue(payload["valid"])
|
||||
self.assertEqual("active", payload["status"])
|
||||
self.assertEqual("auth_disabled", payload["source"])
|
||||
self.assertEqual(2, payload["playableSongCount"])
|
||||
|
||||
def test_token_status_active_degrades_when_catalog_track_files_table_missing(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
player_db_path = Path(tmpdir) / "player.db"
|
||||
catalog_db_path = Path(tmpdir) / "catalog_read.db"
|
||||
sqlite3.connect(catalog_db_path).close()
|
||||
|
||||
with patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
"PLAYER_DB_PATH": str(player_db_path),
|
||||
"CATALOG_DB_PATH": str(catalog_db_path),
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
client = TestClient(create_app(), raise_server_exceptions=False)
|
||||
response = client.get(
|
||||
"/auth/v1/token-status",
|
||||
headers=auth_headers(player_db_path),
|
||||
)
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
payload = response.json()
|
||||
self.assertTrue(payload["valid"])
|
||||
self.assertEqual("active", payload["status"])
|
||||
self.assertIsNone(payload["playableSongCount"])
|
||||
|
||||
def test_auth_headers_reuses_same_token_by_default_for_same_db(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
player_db_path = Path(tmpdir) / "player.db"
|
||||
first = auth_headers(player_db_path)
|
||||
second = auth_headers(player_db_path)
|
||||
|
||||
self.assertEqual(first["Authorization"], second["Authorization"])
|
||||
service = TokenService(str(player_db_path))
|
||||
self.assertEqual(1, len(service.list_tokens(include_revoked=True)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user