137 lines
4.8 KiB
Python
137 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from types import SimpleNamespace
|
|
|
|
import httpx
|
|
|
|
from app.clients.spotify import SpotifyClient
|
|
|
|
|
|
class RecordingHttpClient:
|
|
def __init__(self, responses: list[httpx.Response]) -> None:
|
|
self._responses = list(responses)
|
|
self.calls: list[dict] = []
|
|
|
|
async def request(self, method: str, url: str, **kwargs):
|
|
self.calls.append(
|
|
{
|
|
"method": method,
|
|
"url": url,
|
|
"headers": kwargs.get("headers"),
|
|
"params": kwargs.get("params"),
|
|
"json": kwargs.get("json"),
|
|
}
|
|
)
|
|
if not self._responses:
|
|
raise AssertionError("No queued response for request")
|
|
return self._responses.pop(0)
|
|
|
|
|
|
def make_response(method: str, url: str, status_code: int, *, json_body=None, text_body: str | None = None) -> httpx.Response:
|
|
request = httpx.Request(method, url)
|
|
if json_body is not None:
|
|
return httpx.Response(status_code, request=request, json=json_body)
|
|
return httpx.Response(status_code, request=request, text=text_body or "")
|
|
|
|
|
|
def make_client(http_client: RecordingHttpClient) -> SpotifyClient:
|
|
settings = SimpleNamespace(
|
|
spotify_client_id="id",
|
|
spotify_client_secret="secret",
|
|
spotify_redirect_uri="https://example.test/callback",
|
|
)
|
|
return SpotifyClient(settings, http_client) # type: ignore[arg-type]
|
|
|
|
|
|
class SpotifyClientPlaylistTests(unittest.IsolatedAsyncioTestCase):
|
|
async def test_create_playlist_uses_me_endpoint(self) -> None:
|
|
http_client = RecordingHttpClient(
|
|
[
|
|
make_response(
|
|
"POST",
|
|
"https://api.spotify.com/v1/me/playlists",
|
|
201,
|
|
json_body={
|
|
"id": "pl1",
|
|
"name": "Test Playlist",
|
|
"external_urls": {"spotify": "https://open.spotify.com/playlist/pl1"},
|
|
},
|
|
)
|
|
]
|
|
)
|
|
client = make_client(http_client)
|
|
|
|
payload = await client.create_playlist(
|
|
"token",
|
|
user_id="user123",
|
|
name="Test Playlist",
|
|
description="desc",
|
|
public=False,
|
|
)
|
|
|
|
self.assertEqual(payload["id"], "pl1")
|
|
self.assertEqual(len(http_client.calls), 1)
|
|
call = http_client.calls[0]
|
|
self.assertEqual(call["method"], "POST")
|
|
self.assertEqual(call["url"], "https://api.spotify.com/v1/me/playlists")
|
|
self.assertEqual(call["json"], {"name": "Test Playlist", "description": "desc", "public": False})
|
|
self.assertEqual(call["headers"]["Authorization"], "Bearer token")
|
|
|
|
async def test_delete_playlist_calls_followers_delete(self) -> None:
|
|
http_client = RecordingHttpClient(
|
|
[
|
|
make_response(
|
|
"DELETE",
|
|
"https://api.spotify.com/v1/playlists/pl123/followers",
|
|
200,
|
|
text_body="",
|
|
)
|
|
]
|
|
)
|
|
client = make_client(http_client)
|
|
|
|
await client.delete_playlist("token", "pl123")
|
|
|
|
self.assertEqual(len(http_client.calls), 1)
|
|
call = http_client.calls[0]
|
|
self.assertEqual(call["method"], "DELETE")
|
|
self.assertEqual(call["url"], "https://api.spotify.com/v1/playlists/pl123/followers")
|
|
self.assertEqual(call["headers"]["Authorization"], "Bearer token")
|
|
self.assertIsNone(call["json"])
|
|
|
|
async def test_add_playlist_items_uses_items_endpoint_and_chunks(self) -> None:
|
|
uris = [f"spotify:track:{i:02d}" for i in range(101)]
|
|
http_client = RecordingHttpClient(
|
|
[
|
|
make_response(
|
|
"POST",
|
|
"https://api.spotify.com/v1/playlists/pl999/items",
|
|
201,
|
|
json_body={"snapshot_id": "snap1"},
|
|
),
|
|
make_response(
|
|
"POST",
|
|
"https://api.spotify.com/v1/playlists/pl999/items",
|
|
201,
|
|
json_body={"snapshot_id": "snap2"},
|
|
),
|
|
]
|
|
)
|
|
client = make_client(http_client)
|
|
|
|
await client.add_playlist_items("token", "pl999", uris)
|
|
|
|
self.assertEqual(len(http_client.calls), 2)
|
|
first, second = http_client.calls
|
|
self.assertEqual(first["method"], "POST")
|
|
self.assertEqual(first["url"], "https://api.spotify.com/v1/playlists/pl999/items")
|
|
self.assertEqual(second["url"], "https://api.spotify.com/v1/playlists/pl999/items")
|
|
self.assertEqual(len(first["json"]["uris"]), 100)
|
|
self.assertEqual(len(second["json"]["uris"]), 1)
|
|
self.assertEqual(first["headers"]["Authorization"], "Bearer token")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|