import json import os from contextlib import contextmanager from unittest.mock import patch, Mock from django.apps import apps from django.conf import settings from django.test import TestCase, override_settings from django.urls import reverse from spotipy.client import SpotifyException from django.core.cache import cache from core_images.headers import CacheHeaderValues, CACHE_HEADER @patch("core_images.dsp_clients.Auth0.get_token", new=Mock()) @override_settings(DJANGO_REDIS_IS_ASYNC=False) class IndexViewTests(TestCase): def setUp(self): cache.clear() def test_successful_image_redirect(self): """Successfully redirect to the CDN image URL""" fixture = self.load_fixture("2RyY5yFlJh6jIPfMDhHgyD.json") with patch("core_images.dsp_clients.SpotifyVendor.artist") as mock: mock.return_value = fixture path = reverse( "artist_by_spotify_id", args=["2RyY5yFlJh6jIPfMDhHgyD"] ) response = self.client.get(path, {}, HTTP_ACCEPT="image/*") mock.assert_called_with("2RyY5yFlJh6jIPfMDhHgyD") self.assertEqual(response.status_code, 307) self.assertEqual( response["Location"], "https://i.scdn.co/image/4de6824c66524e4316b316732154bb02ae163a06", ) def test_artist_without_images(self): """For a Spotify artist with no attached image""" fixture = self.load_fixture("4OoQ3ge55V8UZj0v3wqREl.json") with patch("core_images.dsp_clients.SpotifyVendor.artist") as mock: mock.return_value = fixture path = reverse( "artist_by_spotify_id", args=["4OoQ3ge55V8UZj0v3wqREl"] ) response = self.client.get(path, {}, HTTP_ACCEPT="image/*") mock.assert_called_with("4OoQ3ge55V8UZj0v3wqREl") self.assertEqual(response.status_code, 404) def test_missing_artist(self): """For a non-existent Spotify artist""" excp = SpotifyException(404, -1, "Invalid artist Id") with patch("core_images.dsp_clients.SpotifyVendor.artist") as mock: mock.side_effect = excp path = reverse("artist_by_spotify_id", args=["badartist"]) response = self.client.get(path, {}, HTTP_ACCEPT="image/*") mock.assert_called_with("badartist") self.assertEqual(response.status_code, 404) def test_cached_image(self): """ Successfully redirect to the CDN image URL """ fixture = self.load_fixture("2RyY5yFlJh6jIPfMDhHgyD.json") image_url = "https://i.scdn.co/image/4de6824c66524e4316b316732154bb02ae163a06" # noqa with patch("core_images.dsp_clients.SpotifyVendor.artist") as mock: mock.return_value = fixture path = reverse( "artist_by_spotify_id", args=["2RyY5yFlJh6jIPfMDhHgyD"] ) 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 ) # 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) def get_spotify_client(self): this_app = apps.get_app_config("core_images") return this_app.spotify_service.spotify_client @contextmanager def mock_artist(self, mock_obj): try: s = self.get_spotify_client() orig_artist = s.artist s.artist = mock_obj yield mock_obj finally: s.artist = orig_artist