test_views.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. from datetime import datetime, timedelta
  2. from unittest.mock import patch
  3. from django.utils import timezone
  4. import pytest
  5. import time_machine
  6. from django.urls import reverse
  7. from music.models import Track
  8. from podcasts.models import PodcastEpisode
  9. from scrobbles.models import Scrobble
  10. @pytest.mark.django_db
  11. def test_get_not_allowed_from_mopidy(client, valid_auth_token):
  12. url = reverse("scrobbles:mopidy-webhook")
  13. headers = {"Authorization": f"Token {valid_auth_token}"}
  14. response = client.get(url, headers=headers)
  15. assert response.status_code == 405
  16. @pytest.mark.django_db
  17. def test_bad_mopidy_request_data(client, valid_auth_token):
  18. url = reverse("scrobbles:mopidy-webhook")
  19. headers = {"Authorization": f"Token {valid_auth_token}"}
  20. response = client.post(url, headers)
  21. assert response.status_code == 400
  22. assert (
  23. response.data["detail"]
  24. == "JSON parse error - Expecting value: line 1 column 1 (char 0)"
  25. )
  26. @pytest.mark.django_db
  27. @patch("music.utils.lookup_artist_from_mb", return_value={})
  28. @patch(
  29. "music.utils.lookup_album_dict_from_mb",
  30. return_value={"year": "1999", "mb_group_id": 1},
  31. )
  32. @patch("music.utils.lookup_track_from_mb", return_value={})
  33. @patch("music.models.lookup_artist_from_tadb", return_value={})
  34. @patch("music.models.lookup_album_from_tadb", return_value={"year": "1999"})
  35. @patch("music.models.Album.fetch_artwork", return_value=None)
  36. @patch("music.models.Album.scrape_allmusic", return_value=None)
  37. def test_scrobble_mopidy_same_track_different_album(
  38. mock_lookup_artist,
  39. mock_lookup_album,
  40. mock_lookup_track,
  41. mock_lookup_artist_tadb,
  42. mock_lookup_album_tadb,
  43. mock_fetch_artwork,
  44. mock_scrape_allmusic,
  45. client,
  46. mopidy_track,
  47. mopidy_track_diff_album_request_data,
  48. valid_auth_token,
  49. ):
  50. url = reverse("scrobbles:mopidy-webhook")
  51. headers = {"Authorization": f"Token {valid_auth_token}"}
  52. response = client.post(
  53. url,
  54. mopidy_track.request_data,
  55. content_type="application/json",
  56. headers=headers,
  57. )
  58. assert response.status_code == 200
  59. assert response.data == {"scrobble_id": 1}
  60. scrobble = Scrobble.objects.last()
  61. assert scrobble.media_obj.album.name == "Sublime"
  62. response = client.post(
  63. url,
  64. mopidy_track_diff_album_request_data,
  65. content_type="application/json",
  66. )
  67. assert response.status_code == 200
  68. assert response.data == {"scrobble_id": 2}
  69. scrobble = Scrobble.objects.last()
  70. assert scrobble.media_obj.__class__ == Track
  71. assert scrobble.media_obj.album.name == "Sublime"
  72. assert scrobble.media_obj.title == "Same in the End"
  73. @pytest.mark.django_db
  74. @patch(
  75. "podcasts.sources.podcastindex.lookup_podcast_from_podcastindex",
  76. return_value={},
  77. )
  78. def test_scrobble_mopidy_podcast(
  79. mock_lookup_podcast, client, mopidy_podcast_request_data, valid_auth_token
  80. ):
  81. url = reverse("scrobbles:mopidy-webhook")
  82. headers = {"Authorization": f"Token {valid_auth_token}"}
  83. response = client.post(
  84. url,
  85. mopidy_podcast_request_data,
  86. content_type="application/json",
  87. headers=headers,
  88. )
  89. assert response.status_code == 200
  90. assert response.data == {"scrobble_id": 1}
  91. scrobble = Scrobble.objects.get(id=1)
  92. assert scrobble.media_obj.__class__ == PodcastEpisode
  93. assert scrobble.media_obj.title == "Up First"
  94. @pytest.mark.django_db
  95. @patch("music.utils.lookup_artist_from_mb", return_value={})
  96. @patch(
  97. "music.utils.lookup_album_dict_from_mb",
  98. return_value={"year": "1999", "mb_group_id": 1},
  99. )
  100. @patch("music.utils.lookup_track_from_mb", return_value={})
  101. @patch("music.models.lookup_artist_from_tadb", return_value={})
  102. @patch("music.models.lookup_album_from_tadb", return_value={"year": "1999"})
  103. @patch("music.models.Album.fetch_artwork", return_value=None)
  104. @patch("music.models.Album.scrape_allmusic", return_value=None)
  105. def test_scrobble_jellyfin_track(
  106. mock_lookup_artist,
  107. mock_lookup_album,
  108. mock_lookup_track,
  109. mock_lookup_artist_tadb,
  110. mock_lookup_album_tadb,
  111. mock_fetch_artwork,
  112. mock_scrape_allmusic,
  113. client,
  114. jellyfin_track,
  115. valid_auth_token,
  116. ):
  117. url = reverse("scrobbles:jellyfin-webhook")
  118. headers = {"Authorization": f"Token {valid_auth_token}"}
  119. with time_machine.travel(datetime(2024, 1, 14, 12, 00, 1)):
  120. jellyfin_track.request_data["UtcTimestamp"] = timezone.now().strftime(
  121. "%Y-%m-%d %H:%M:%S"
  122. )
  123. response = client.post(
  124. url,
  125. jellyfin_track.request_json,
  126. content_type="application/json",
  127. headers=headers,
  128. )
  129. assert response.status_code == 200
  130. assert response.data == {"scrobble_id": 1}
  131. scrobble = Scrobble.objects.get(id=1)
  132. assert scrobble.media_obj.__class__ == Track
  133. assert scrobble.media_obj.title == "Emotion"
  134. @pytest.mark.django_db
  135. @patch("music.utils.lookup_artist_from_mb", return_value={})
  136. @patch(
  137. "music.utils.lookup_album_dict_from_mb",
  138. return_value={"year": "1999", "mb_group_id": 1},
  139. )
  140. @patch("music.utils.lookup_track_from_mb", return_value={})
  141. @patch("music.models.lookup_artist_from_tadb", return_value={})
  142. @patch("music.models.lookup_album_from_tadb", return_value={"year": "1999"})
  143. @patch("music.models.Album.fetch_artwork", return_value=None)
  144. @patch("music.models.Album.scrape_allmusic", return_value=None)
  145. def test_scrobble_jellyfin_track_update(
  146. mock_lookup_artist,
  147. mock_lookup_album,
  148. mock_lookup_track,
  149. mock_lookup_artist_tadb,
  150. mock_lookup_album_tadb,
  151. mock_fetch_artwork,
  152. mock_scrape_allmusic,
  153. test_track,
  154. client,
  155. jellyfin_track,
  156. valid_auth_token,
  157. ):
  158. Scrobble.objects.create(
  159. timestamp=timezone.now() - timedelta(minutes=0.5),
  160. track=Track.objects.first(),
  161. user_id=1,
  162. )
  163. url = reverse("scrobbles:jellyfin-webhook")
  164. headers = {"Authorization": f"Token {valid_auth_token}"}
  165. jellyfin_track.request_data["UtcTimestamp"] = timezone.now().strftime(
  166. "%Y-%m-%d %H:%M:%S"
  167. )
  168. response = client.post(
  169. url,
  170. jellyfin_track.request_json,
  171. content_type="application/json",
  172. headers=headers,
  173. )
  174. assert response.status_code == 200
  175. assert response.data == {"scrobble_id": 1}
  176. scrobble = Scrobble.objects.get(id=1)
  177. assert scrobble.media_obj.__class__ == Track
  178. assert scrobble.media_obj.title == "Emotion"
  179. @pytest.mark.django_db
  180. @patch("music.utils.lookup_artist_from_mb", return_value={})
  181. @patch(
  182. "music.utils.lookup_album_dict_from_mb",
  183. return_value={"year": "1999", "mb_group_id": 1},
  184. )
  185. @patch("music.utils.lookup_track_from_mb", return_value={})
  186. @patch("music.models.lookup_artist_from_tadb", return_value={})
  187. @patch("music.models.lookup_album_from_tadb", return_value={"year": "1999"})
  188. @patch("music.models.Album.fetch_artwork", return_value=None)
  189. @patch("music.models.Album.scrape_allmusic", return_value=None)
  190. def test_scrobble_jellyfin_track_create_new(
  191. mock_lookup_artist,
  192. mock_lookup_album,
  193. mock_lookup_track,
  194. mock_lookup_artist_tadb,
  195. mock_lookup_album_tadb,
  196. mock_fetch_artwork,
  197. mock_scrape_allmusic,
  198. test_track,
  199. client,
  200. jellyfin_track,
  201. valid_auth_token,
  202. ):
  203. url = reverse("scrobbles:jellyfin-webhook")
  204. headers = {"Authorization": f"Token {valid_auth_token}"}
  205. Scrobble.objects.create(
  206. timestamp=timezone.now() - timedelta(minutes=1),
  207. track=Track.objects.first(),
  208. user_id=1,
  209. )
  210. jellyfin_track.request_data["UtcTimestamp"] = timezone.now().strftime(
  211. "%Y-%m-%d %H:%M:%S"
  212. )
  213. response = client.post(
  214. url,
  215. jellyfin_track.request_json,
  216. content_type="application/json",
  217. headers=headers,
  218. )
  219. assert response.status_code == 200
  220. assert response.data == {"scrobble_id": 2}
  221. scrobble = Scrobble.objects.get(id=1)
  222. assert scrobble.media_obj.__class__ == Track
  223. assert scrobble.media_obj.title == "Emotion"