import json import os from unittest.mock import patch, Mock from parameterized import parameterized from django.conf import settings from django.test import TestCase, override_settings from django.urls import reverse from django.core.cache import cache from spotipy.client import SpotifyException from core_images.headers import CacheHeaderValues, CACHE_HEADER from core_images.consts import ( SMALL_RESOLUTION, MEDIUM_RESOLUTION, LARGE_RESOLUTION, ) @patch("core_images.dsp_clients.Auth0.get_token", new=Mock()) @override_settings(DJANGO_REDIS_IS_ASYNC=False) class AlbumBySpotifyIdIntegrationTests(TestCase): def setUp(self): cache.clear() def test_successful_image_redirect(self): """ Successfully redirect to the CDN image URL """ fixture = self.load_fixture("4vQc378UGRZAaJemArhMpv.json") with patch("core_images.dsp_clients.SpotifyVendor.album") as mock: mock.return_value = fixture path = reverse( "album_by_spotify_id", args=["4vQc378UGRZAaJemArhMpv"] ) response = self.client.get(path, {}, HTTP_ACCEPT="image/*") mock.assert_called_with("4vQc378UGRZAaJemArhMpv") self.assertEqual(response.status_code, 307) self.assertEqual( response["Location"], "https://i.scdn.co/image/ab67616d00001e02e9352198fb1eb4bf8fa22518", ) def test_album_not_found(self): """ When Spotify doesn’t recognize the album, return a 404 """ excp = SpotifyException(404, -1, "Invalid playlist Id") with patch("core_images.dsp_clients.SpotifyVendor.album") as mock: mock.side_effect = excp path = reverse("album_by_spotify_id", args=["badfake"]) response = self.client.get(path, {}, HTTP_ACCEPT="image/*") mock.assert_called_with("badfake") self.assertEqual(response.status_code, 404) def test_cached_image(self): fixture = self.load_fixture("4vQc378UGRZAaJemArhMpv.json") image_url = "https://i.scdn.co/image/ab67616d00001e02e9352198fb1eb4bf8fa22518" # noqa with patch("core_images.dsp_clients.SpotifyVendor.album") as mock: mock.return_value = fixture path = reverse( "album_by_spotify_id", args=["4vQc378UGRZAaJemArhMpv"] ) response_1 = self.client.get(path, {}, HTTP_ACCEPT="image/*") response_2 = self.client.get(path, {}, HTTP_ACCEPT="image/*") self.assertEqual(mock.call_count, 1) self.assertEqual(response_1.status_code, 307) self.assertEqual(response_1["Location"], image_url) self.assertEqual( response_1.get(CACHE_HEADER), CacheHeaderValues.MISS.value ) self.assertEqual(response_2.status_code, 307) self.assertEqual(response_2["Location"], image_url) self.assertEqual( response_2.get(CACHE_HEADER), CacheHeaderValues.HIT.value ) @parameterized.expand( [ SMALL_RESOLUTION, MEDIUM_RESOLUTION, LARGE_RESOLUTION, ] ) def test_image_resolutions(self, resolution): resolutions = { SMALL_RESOLUTION: "https://i.scdn.co/image/ab67616d00001e02e9352198fb1eb4bf8fa22518", # noqa MEDIUM_RESOLUTION: "https://i.scdn.co/image/ab67616d00001e02e9352198fb1eb4bf8fa22518", # noqa LARGE_RESOLUTION: "https://i.scdn.co/image/ab67616d0000b273e9352198fb1eb4bf8fa22518", # noqa } fixture = self.load_fixture("4vQc378UGRZAaJemArhMpv.json") with patch("core_images.dsp_clients.SpotifyVendor.album") as mock: mock.return_value = fixture path = reverse( "album_by_spotify_id", args=["4vQc378UGRZAaJemArhMpv"] ) response = self.client.get( path, {"resolution": resolution}, HTTP_ACCEPT="image/*" ) mock.assert_called_with("4vQc378UGRZAaJemArhMpv") self.assertEqual(response.status_code, 307) self.assertEqual( response["Location"], resolutions.get(resolution), ) # Helpers def load_fixture(self, filename): fixture_path = os.path.join( settings.BASE_DIR, "tests", "fixtures", "spotipy", filename ) with open(fixture_path) as f: return json.load(f)