Cache radio queryset. New api endpoint for radio tracks : api/v2/radios/sessions/$sessionid/tracks?count=$count
This commit is contained in:
parent
04acd056e6
commit
4ad806b8e9
13 changed files with 845 additions and 77 deletions
|
|
@ -2,8 +2,8 @@ import json
|
|||
import random
|
||||
|
||||
import pytest
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.urls import reverse
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from funkwhale_api.favorites.models import TrackFavorite
|
||||
from funkwhale_api.radios import models, radios, serializers
|
||||
|
|
@ -98,7 +98,7 @@ def test_can_get_choices_for_custom_radio(factories):
|
|||
session = factories["radios.CustomRadioSession"](
|
||||
custom_radio__config=[{"type": "artist", "ids": [artist.pk]}]
|
||||
)
|
||||
choices = session.radio.get_choices(filter_playable=False)
|
||||
choices = session.radio(api_version=1).get_choices(filter_playable=False)
|
||||
|
||||
expected = [t.pk for t in tracks]
|
||||
assert list(choices.values_list("id", flat=True)) == expected
|
||||
|
|
@ -191,16 +191,17 @@ def test_can_get_track_for_session_from_api(factories, logged_in_api_client):
|
|||
|
||||
|
||||
def test_related_object_radio_validate_related_object(factories):
|
||||
user = factories["users.User"]()
|
||||
# cannot start without related object
|
||||
radio = radios.ArtistRadio()
|
||||
radio = {"radio_type": "tag"}
|
||||
serializer = serializers.RadioSessionSerializer()
|
||||
with pytest.raises(ValidationError):
|
||||
radio.start_session(user)
|
||||
serializer.validate(data=radio)
|
||||
|
||||
# cannot start with bad related object type
|
||||
radio = radios.ArtistRadio()
|
||||
radio = {"radio_type": "tag", "related_object": "whatever"}
|
||||
serializer = serializers.RadioSessionSerializer()
|
||||
with pytest.raises(ValidationError):
|
||||
radio.start_session(user, related_object=user)
|
||||
serializer.validate(data=radio)
|
||||
|
||||
|
||||
def test_can_start_artist_radio(factories):
|
||||
|
|
@ -391,7 +392,7 @@ def test_get_choices_for_custom_radio_exclude_artist(factories):
|
|||
{"type": "artist", "ids": [excluded_artist.pk], "not": True},
|
||||
]
|
||||
)
|
||||
choices = session.radio.get_choices(filter_playable=False)
|
||||
choices = session.radio(api_version=1).get_choices(filter_playable=False)
|
||||
|
||||
expected = [u.track.pk for u in included_uploads]
|
||||
assert list(choices.values_list("id", flat=True)) == expected
|
||||
|
|
@ -409,7 +410,7 @@ def test_get_choices_for_custom_radio_exclude_tag(factories):
|
|||
{"type": "tag", "names": ["rock"], "not": True},
|
||||
]
|
||||
)
|
||||
choices = session.radio.get_choices(filter_playable=False)
|
||||
choices = session.radio(api_version=1).get_choices(filter_playable=False)
|
||||
|
||||
expected = [u.track.pk for u in included_uploads]
|
||||
assert list(choices.values_list("id", flat=True)) == expected
|
||||
|
|
@ -429,28 +430,3 @@ def test_can_start_custom_multiple_radio_from_api(api_client, factories):
|
|||
format="json",
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_can_start_periodic_jams_troi_radio_from_api(api_client, factories):
|
||||
factories["music.Track"].create_batch(5)
|
||||
url = reverse("api:v1:radios:sessions-list")
|
||||
config = {"patch": "periodic-jams", "type": "daily-jams"}
|
||||
response = api_client.post(
|
||||
url,
|
||||
{"radio_type": "troi", "config": config},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
# to do : send error to api ?
|
||||
def test_can_catch_troi_radio_error(api_client, factories):
|
||||
factories["music.Track"].create_batch(5)
|
||||
url = reverse("api:v1:radios:sessions-list")
|
||||
config = {"patch": "periodic-jams", "type": "not_existing_type"}
|
||||
response = api_client.post(
|
||||
url,
|
||||
{"radio_type": "troi", "config": config},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
|
|
|||
144
api/tests/radios/test_radios_v2.py
Normal file
144
api/tests/radios/test_radios_v2.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
import json
|
||||
import logging
|
||||
import pickle
|
||||
import random
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.urls import reverse
|
||||
|
||||
from funkwhale_api.favorites.models import TrackFavorite
|
||||
from funkwhale_api.radios import models, radios_v2
|
||||
|
||||
|
||||
def test_can_get_track_for_session_from_api_v2(factories, logged_in_api_client):
|
||||
actor = logged_in_api_client.user.create_actor()
|
||||
track = factories["music.Upload"](
|
||||
library__actor=actor, import_status="finished"
|
||||
).track
|
||||
url = reverse("api:v2:radios:sessions-list")
|
||||
response = logged_in_api_client.post(url, {"radio_type": "random"})
|
||||
session = models.RadioSession.objects.latest("id")
|
||||
|
||||
url = reverse("api:v2:radios:sessions-tracks", kwargs={"pk": session.pk})
|
||||
response = logged_in_api_client.get(url, {"session": session.pk})
|
||||
data = json.loads(response.content.decode("utf-8"))
|
||||
|
||||
assert data[0]["id"] == track.pk
|
||||
|
||||
next_track = factories["music.Upload"](
|
||||
library__actor=actor, import_status="finished"
|
||||
).track
|
||||
response = logged_in_api_client.get(url, {"session": session.pk})
|
||||
data = json.loads(response.content.decode("utf-8"))
|
||||
|
||||
assert data[0]["id"] == next_track.id
|
||||
|
||||
|
||||
def test_can_use_radio_session_to_filter_choices_v2(factories):
|
||||
factories["music.Upload"].create_batch(10)
|
||||
user = factories["users.User"]()
|
||||
radio = radios_v2.RandomRadio()
|
||||
session = radio.start_session(user)
|
||||
|
||||
radio.pick_many(quantity=10, filter_playable=False)
|
||||
|
||||
# ensure 10 different tracks have been suggested
|
||||
tracks_id = [
|
||||
session_track.track.pk for session_track in session.session_tracks.all()
|
||||
]
|
||||
assert len(set(tracks_id)) == 10
|
||||
|
||||
|
||||
def test_session_radio_excludes_previous_picks_v2(factories, logged_in_api_client):
|
||||
tracks = factories["music.Track"].create_batch(5)
|
||||
url = reverse("api:v2:radios:sessions-list")
|
||||
response = logged_in_api_client.post(url, {"radio_type": "random"})
|
||||
session = models.RadioSession.objects.latest("id")
|
||||
url = reverse("api:v2:radios:sessions-tracks", kwargs={"pk": session.pk})
|
||||
|
||||
previous_choices = []
|
||||
|
||||
for i in range(5):
|
||||
response = logged_in_api_client.get(
|
||||
url, {"session": session.pk, "filter_playable": False}
|
||||
)
|
||||
pick = json.loads(response.content.decode("utf-8"))
|
||||
assert pick[0]["title"] not in previous_choices
|
||||
assert pick[0]["title"] in [t.title for t in tracks]
|
||||
previous_choices.append(pick[0]["title"])
|
||||
|
||||
response = logged_in_api_client.get(url, {"session": session.pk})
|
||||
assert (
|
||||
json.loads(response.content.decode("utf-8"))
|
||||
== "Radio doesn't have more candidates"
|
||||
)
|
||||
|
||||
|
||||
def test_can_get_choices_for_favorites_radio_v2(factories):
|
||||
files = factories["music.Upload"].create_batch(10)
|
||||
tracks = [f.track for f in files]
|
||||
user = factories["users.User"]()
|
||||
for i in range(5):
|
||||
TrackFavorite.add(track=random.choice(tracks), user=user)
|
||||
|
||||
radio = radios_v2.FavoritesRadio()
|
||||
session = radio.start_session(user=user)
|
||||
choices = session.radio(api_version=2).get_choices(
|
||||
quantity=100, filter_playable=False
|
||||
)
|
||||
|
||||
assert len(choices) == user.track_favorites.all().count()
|
||||
|
||||
for favorite in user.track_favorites.all():
|
||||
assert favorite.track in choices
|
||||
|
||||
|
||||
def test_can_get_choices_for_custom_radio_v2(factories):
|
||||
artist = factories["music.Artist"]()
|
||||
files = factories["music.Upload"].create_batch(5, track__artist=artist)
|
||||
tracks = [f.track for f in files]
|
||||
factories["music.Upload"].create_batch(5)
|
||||
|
||||
session = factories["radios.CustomRadioSession"](
|
||||
custom_radio__config=[{"type": "artist", "ids": [artist.pk]}]
|
||||
)
|
||||
choices = session.radio(api_version=2).get_choices(
|
||||
quantity=1, filter_playable=False
|
||||
)
|
||||
|
||||
expected = [t.pk for t in tracks]
|
||||
for t in choices:
|
||||
assert t.id in expected
|
||||
|
||||
|
||||
def test_can_cache_radio_track(factories):
|
||||
uploads = factories["music.Track"].create_batch(10)
|
||||
user = factories["users.User"]()
|
||||
radio = radios_v2.RandomRadio()
|
||||
session = radio.start_session(user)
|
||||
picked = session.radio(api_version=2).pick_many(quantity=1, filter_playable=False)
|
||||
assert len(picked) == 1
|
||||
for t in pickle.loads(cache.get(f"radiotracks{session.id}")):
|
||||
assert t in uploads
|
||||
|
||||
|
||||
def test_regenerate_cache_if_not_enought_tracks_in_it(
|
||||
factories, caplog, logged_in_api_client
|
||||
):
|
||||
logger = logging.getLogger("funkwhale_api.radios.radios_v2")
|
||||
caplog.set_level(logging.INFO)
|
||||
logger.addHandler(caplog.handler)
|
||||
|
||||
factories["music.Track"].create_batch(10)
|
||||
factories["users.User"]()
|
||||
url = reverse("api:v2:radios:sessions-list")
|
||||
response = logged_in_api_client.post(url, {"radio_type": "random"})
|
||||
session = models.RadioSession.objects.latest("id")
|
||||
url = reverse("api:v2:radios:sessions-tracks", kwargs={"pk": session.pk})
|
||||
logged_in_api_client.get(url, {"count": 9, "filter_playable": False})
|
||||
response = logged_in_api_client.get(url, {"count": 10, "filter_playable": False})
|
||||
pick = json.loads(response.content.decode("utf-8"))
|
||||
assert (
|
||||
"Not enough radio tracks in cache. Trying to generate new cache" in caplog.text
|
||||
)
|
||||
assert len(pick) == 1
|
||||
Loading…
Add table
Add a link
Reference in a new issue