kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
658 wiersze
22 KiB
Python
658 wiersze
22 KiB
Python
import pytest
|
|
import uuid
|
|
|
|
from funkwhale_api.common import serializers as common_serializers
|
|
from funkwhale_api.federation import serializers as federation_serializers
|
|
from funkwhale_api.music import licenses
|
|
from funkwhale_api.music import models
|
|
from funkwhale_api.music import serializers
|
|
from funkwhale_api.music import tasks
|
|
|
|
|
|
def test_license_serializer():
|
|
"""
|
|
We serializer all licenses to ensure we have valid hardcoded data
|
|
"""
|
|
for data in licenses.LICENSES:
|
|
expected = {
|
|
"id": data["identifiers"][0],
|
|
"code": data["code"],
|
|
"name": data["name"],
|
|
"url": data["url"],
|
|
"redistribute": data["redistribute"],
|
|
"derivative": data["derivative"],
|
|
"commercial": data["commercial"],
|
|
"attribution": data["attribution"],
|
|
"copyleft": data["copyleft"],
|
|
}
|
|
|
|
serializer = serializers.LicenseSerializer(data)
|
|
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_artist_album_serializer(factories, to_api_date):
|
|
track = factories["music.Track"](album__with_cover=True)
|
|
album = track.album
|
|
album = album.__class__.objects.with_tracks_count().get(pk=album.pk)
|
|
expected = {
|
|
"id": album.id,
|
|
"fid": album.fid,
|
|
"mbid": str(album.mbid),
|
|
"title": album.title,
|
|
"artist": album.artist.id,
|
|
"creation_date": to_api_date(album.creation_date),
|
|
"tracks_count": 1,
|
|
"is_playable": None,
|
|
"cover": common_serializers.AttachmentSerializer(album.attachment_cover).data,
|
|
"release_date": to_api_date(album.release_date),
|
|
"is_local": album.is_local,
|
|
}
|
|
serializer = serializers.ArtistAlbumSerializer(album)
|
|
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_artist_with_albums_serializer(factories, to_api_date):
|
|
actor = factories["federation.Actor"]()
|
|
track = factories["music.Track"](
|
|
album__artist__attributed_to=actor, album__artist__with_cover=True
|
|
)
|
|
artist = track.artist
|
|
artist = artist.__class__.objects.with_albums().get(pk=artist.pk)
|
|
album = list(artist.albums.all())[0]
|
|
setattr(artist, "_prefetched_tracks", range(42))
|
|
expected = {
|
|
"id": artist.id,
|
|
"fid": artist.fid,
|
|
"mbid": str(artist.mbid),
|
|
"name": artist.name,
|
|
"is_local": artist.is_local,
|
|
"content_category": artist.content_category,
|
|
"creation_date": to_api_date(artist.creation_date),
|
|
"albums": [serializers.ArtistAlbumSerializer(album).data],
|
|
"tags": [],
|
|
"attributed_to": federation_serializers.APIActorSerializer(actor).data,
|
|
"tracks_count": 42,
|
|
"cover": common_serializers.AttachmentSerializer(artist.attachment_cover).data,
|
|
"channel": None,
|
|
}
|
|
serializer = serializers.ArtistWithAlbumsSerializer(artist)
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_artist_with_albums_serializer_channel(factories, to_api_date):
|
|
actor = factories["federation.Actor"]()
|
|
channel = factories["audio.Channel"](attributed_to=actor, artist__with_cover=True)
|
|
track = factories["music.Track"](album__artist=channel.artist)
|
|
artist = track.artist
|
|
artist = artist.__class__.objects.with_albums().get(pk=artist.pk)
|
|
album = list(artist.albums.all())[0]
|
|
setattr(artist, "_prefetched_tracks", range(42))
|
|
expected = {
|
|
"id": artist.id,
|
|
"fid": artist.fid,
|
|
"mbid": str(artist.mbid),
|
|
"name": artist.name,
|
|
"is_local": artist.is_local,
|
|
"content_category": artist.content_category,
|
|
"creation_date": to_api_date(artist.creation_date),
|
|
"albums": [serializers.ArtistAlbumSerializer(album).data],
|
|
"tags": [],
|
|
"attributed_to": federation_serializers.APIActorSerializer(actor).data,
|
|
"tracks_count": 42,
|
|
"cover": common_serializers.AttachmentSerializer(artist.attachment_cover).data,
|
|
"channel": {
|
|
"uuid": str(channel.uuid),
|
|
"actor": {
|
|
"full_username": channel.actor.full_username,
|
|
"preferred_username": channel.actor.preferred_username,
|
|
"domain": channel.actor.domain_id,
|
|
},
|
|
},
|
|
}
|
|
serializer = serializers.ArtistWithAlbumsSerializer(artist)
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_upload_serializer(factories, to_api_date):
|
|
upload = factories["music.Upload"]()
|
|
|
|
expected = {
|
|
"uuid": str(upload.uuid),
|
|
"filename": upload.filename,
|
|
"track": serializers.TrackSerializer(upload.track).data,
|
|
"duration": upload.duration,
|
|
"mimetype": upload.mimetype,
|
|
"bitrate": upload.bitrate,
|
|
"size": upload.size,
|
|
"library": serializers.LibraryForOwnerSerializer(upload.library).data,
|
|
"creation_date": to_api_date(upload.creation_date),
|
|
"import_date": None,
|
|
"import_status": "pending",
|
|
}
|
|
serializer = serializers.UploadSerializer(upload)
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_upload_owner_serializer(factories, to_api_date):
|
|
upload = factories["music.Upload"](
|
|
import_status="success",
|
|
import_details={"hello": "world"},
|
|
import_metadata={"import": "metadata"},
|
|
import_reference="ref",
|
|
metadata={"test": "metadata"},
|
|
source="upload://test",
|
|
)
|
|
|
|
expected = {
|
|
"uuid": str(upload.uuid),
|
|
"filename": upload.filename,
|
|
"track": serializers.TrackSerializer(upload.track).data,
|
|
"duration": upload.duration,
|
|
"mimetype": upload.mimetype,
|
|
"bitrate": upload.bitrate,
|
|
"size": upload.size,
|
|
"library": serializers.LibraryForOwnerSerializer(upload.library).data,
|
|
"creation_date": to_api_date(upload.creation_date),
|
|
"metadata": {"test": "metadata"},
|
|
"import_metadata": {"import": "metadata"},
|
|
"import_date": None,
|
|
"import_status": "success",
|
|
"import_details": {"hello": "world"},
|
|
"source": "upload://test",
|
|
"import_reference": "ref",
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(upload)
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_album_serializer(factories, to_api_date):
|
|
actor = factories["federation.Actor"]()
|
|
track1 = factories["music.Track"](
|
|
position=2, album__attributed_to=actor, album__with_cover=True
|
|
)
|
|
factories["music.Track"](position=1, album=track1.album)
|
|
album = track1.album
|
|
expected = {
|
|
"id": album.id,
|
|
"fid": album.fid,
|
|
"mbid": str(album.mbid),
|
|
"title": album.title,
|
|
"artist": serializers.SimpleArtistSerializer(album.artist).data,
|
|
"creation_date": to_api_date(album.creation_date),
|
|
"is_playable": False,
|
|
"duration": 0,
|
|
"cover": common_serializers.AttachmentSerializer(album.attachment_cover).data,
|
|
"release_date": to_api_date(album.release_date),
|
|
"tracks_count": 2,
|
|
"is_local": album.is_local,
|
|
"tags": [],
|
|
"attributed_to": federation_serializers.APIActorSerializer(actor).data,
|
|
}
|
|
serializer = serializers.AlbumSerializer(
|
|
album.__class__.objects.with_tracks_count().get(pk=album.pk)
|
|
)
|
|
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_track_album_serializer(factories, to_api_date):
|
|
actor = factories["federation.Actor"]()
|
|
track1 = factories["music.Track"](
|
|
position=2, album__attributed_to=actor, album__with_cover=True
|
|
)
|
|
factories["music.Track"](position=1, album=track1.album)
|
|
album = track1.album
|
|
expected = {
|
|
"id": album.id,
|
|
"fid": album.fid,
|
|
"mbid": str(album.mbid),
|
|
"title": album.title,
|
|
"artist": serializers.SimpleArtistSerializer(album.artist).data,
|
|
"creation_date": to_api_date(album.creation_date),
|
|
"is_playable": False,
|
|
"cover": common_serializers.AttachmentSerializer(album.attachment_cover).data,
|
|
"release_date": to_api_date(album.release_date),
|
|
"tracks_count": 2,
|
|
"duration": 0,
|
|
"is_local": album.is_local,
|
|
"tags": [],
|
|
"attributed_to": federation_serializers.APIActorSerializer(actor).data,
|
|
}
|
|
serializer = serializers.AlbumSerializer(
|
|
album.__class__.objects.with_tracks_count().get(pk=album.pk)
|
|
)
|
|
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_track_serializer(factories, to_api_date):
|
|
actor = factories["federation.Actor"]()
|
|
upload = factories["music.Upload"](
|
|
track__license="cc-by-4.0",
|
|
track__copyright="test",
|
|
track__disc_number=2,
|
|
track__attributed_to=actor,
|
|
track__with_cover=True,
|
|
)
|
|
track = upload.track
|
|
setattr(track, "playable_uploads", [upload])
|
|
expected = {
|
|
"id": track.id,
|
|
"fid": track.fid,
|
|
"artist": serializers.SimpleArtistSerializer(track.artist).data,
|
|
"album": serializers.TrackAlbumSerializer(track.album).data,
|
|
"mbid": str(track.mbid),
|
|
"title": track.title,
|
|
"position": track.position,
|
|
"disc_number": track.disc_number,
|
|
"uploads": [serializers.serialize_upload(upload)],
|
|
"creation_date": to_api_date(track.creation_date),
|
|
"listen_url": track.listen_url,
|
|
"license": upload.track.license.code,
|
|
"copyright": upload.track.copyright,
|
|
"is_local": upload.track.is_local,
|
|
"tags": [],
|
|
"attributed_to": federation_serializers.APIActorSerializer(actor).data,
|
|
"cover": common_serializers.AttachmentSerializer(track.attachment_cover).data,
|
|
"downloads_count": track.downloads_count,
|
|
"is_playable": bool(track.playable_uploads),
|
|
}
|
|
serializer = serializers.TrackSerializer(track)
|
|
assert serializer.data == expected
|
|
|
|
|
|
def test_user_cannot_bind_file_to_a_not_owned_library(factories):
|
|
user = factories["users.User"]()
|
|
library = factories["music.Library"]()
|
|
|
|
s = serializers.UploadForOwnerSerializer(
|
|
data={"library": library.uuid, "source": "upload://test"},
|
|
context={"user": user},
|
|
)
|
|
assert s.is_valid() is False
|
|
assert "library" in s.errors
|
|
|
|
|
|
def test_user_can_create_file_in_own_library(factories, uploaded_audio_file):
|
|
user = factories["users.User"]()
|
|
library = factories["music.Library"](actor__user=user)
|
|
s = serializers.UploadForOwnerSerializer(
|
|
data={
|
|
"library": library.uuid,
|
|
"source": "upload://test",
|
|
"audio_file": uploaded_audio_file,
|
|
},
|
|
context={"user": user},
|
|
)
|
|
assert s.is_valid(raise_exception=True) is True
|
|
upload = s.save()
|
|
|
|
assert upload.library == library
|
|
|
|
|
|
def test_create_file_checks_for_user_quota(
|
|
factories, preferences, uploaded_audio_file, mocker
|
|
):
|
|
mocker.patch(
|
|
"funkwhale_api.users.models.User.get_quota_status",
|
|
return_value={"remaining": 0},
|
|
)
|
|
user = factories["users.User"]()
|
|
library = factories["music.Library"](actor__user=user)
|
|
s = serializers.UploadForOwnerSerializer(
|
|
data={
|
|
"library": library.uuid,
|
|
"source": "upload://test",
|
|
"audio_file": uploaded_audio_file,
|
|
},
|
|
context={"user": user},
|
|
)
|
|
assert s.is_valid() is False
|
|
assert s.errors["non_field_errors"] == ["upload_quota_reached"]
|
|
|
|
|
|
def test_manage_upload_action_delete(factories, queryset_equal_list, mocker):
|
|
dispatch = mocker.patch("funkwhale_api.federation.routes.outbox.dispatch")
|
|
library1 = factories["music.Library"]()
|
|
library2 = factories["music.Library"]()
|
|
library1_uploads = factories["music.Upload"].create_batch(size=3, library=library1)
|
|
library2_uploads = factories["music.Upload"].create_batch(size=3, library=library2)
|
|
s = serializers.UploadActionSerializer(queryset=None)
|
|
|
|
s.handle_delete(library1_uploads[0].__class__.objects.all())
|
|
|
|
assert library1_uploads[0].__class__.objects.count() == 0
|
|
dispatch.assert_any_call(
|
|
{"type": "Delete", "object": {"type": "Audio"}},
|
|
context={"uploads": library1_uploads},
|
|
)
|
|
dispatch.assert_any_call(
|
|
{"type": "Delete", "object": {"type": "Audio"}},
|
|
context={"uploads": library2_uploads},
|
|
)
|
|
|
|
|
|
def test_manage_upload_action_relaunch_import(factories, mocker):
|
|
m = mocker.patch("funkwhale_api.common.utils.on_commit")
|
|
|
|
# this one is finished and should stay as is
|
|
finished = factories["music.Upload"](import_status="finished")
|
|
draft = factories["music.Upload"](import_status="draft")
|
|
|
|
to_relaunch = [
|
|
factories["music.Upload"](import_status="pending"),
|
|
factories["music.Upload"](import_status="skipped"),
|
|
factories["music.Upload"](import_status="errored"),
|
|
]
|
|
s = serializers.UploadActionSerializer(queryset=None)
|
|
|
|
s.handle_relaunch_import(models.Upload.objects.all())
|
|
|
|
for obj in to_relaunch:
|
|
obj.refresh_from_db()
|
|
assert obj.import_status == "pending"
|
|
m.assert_any_call(tasks.process_upload.delay, upload_id=obj.pk)
|
|
|
|
finished.refresh_from_db()
|
|
assert finished.import_status == "finished"
|
|
draft.refresh_from_db()
|
|
assert draft.import_status == "draft"
|
|
assert m.call_count == 3
|
|
|
|
|
|
def test_manage_upload_action_publish(factories, mocker):
|
|
m = mocker.patch("funkwhale_api.common.utils.on_commit")
|
|
|
|
draft = factories["music.Upload"](import_status="draft")
|
|
s = serializers.UploadActionSerializer(queryset=None)
|
|
|
|
s.handle_publish(models.Upload.objects.all())
|
|
|
|
draft.refresh_from_db()
|
|
assert draft.import_status == "pending"
|
|
m.assert_any_call(tasks.process_upload.delay, upload_id=draft.pk)
|
|
|
|
|
|
def test_serialize_upload(factories):
|
|
upload = factories["music.Upload"]()
|
|
|
|
expected = {
|
|
"listen_url": upload.listen_url,
|
|
"uuid": str(upload.uuid),
|
|
"size": upload.size,
|
|
"bitrate": upload.bitrate,
|
|
"mimetype": upload.mimetype,
|
|
"extension": upload.extension,
|
|
"duration": upload.duration,
|
|
"is_local": False,
|
|
}
|
|
|
|
data = serializers.serialize_upload(upload)
|
|
assert data == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"field,before,after",
|
|
[
|
|
("privacy_level", "me", "everyone"),
|
|
("name", "Before", "After"),
|
|
("description", "Before", "After"),
|
|
],
|
|
)
|
|
def test_update_library_privacy_level_broadcasts_to_followers(
|
|
factories, field, before, after, mocker
|
|
):
|
|
dispatch = mocker.patch("funkwhale_api.federation.routes.outbox.dispatch")
|
|
library = factories["music.Library"](**{field: before})
|
|
|
|
serializer = serializers.LibraryForOwnerSerializer(
|
|
library, data={field: after}, partial=True
|
|
)
|
|
assert serializer.is_valid(raise_exception=True)
|
|
serializer.save()
|
|
|
|
dispatch.assert_called_once_with(
|
|
{"type": "Update", "object": {"type": "Library"}}, context={"library": library}
|
|
)
|
|
|
|
|
|
def test_upload_with_channel(factories, uploaded_audio_file):
|
|
channel = factories["audio.Channel"](attributed_to__local=True)
|
|
user = channel.attributed_to.user
|
|
data = {
|
|
"channel": channel.uuid,
|
|
"audio_file": uploaded_audio_file,
|
|
"import_status": "draft",
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
assert serializer.is_valid(raise_exception=True) is True
|
|
upload = serializer.save()
|
|
|
|
assert upload.library == channel.library
|
|
|
|
|
|
def test_upload_with_not_owned_channel_fails(factories, uploaded_audio_file):
|
|
channel = factories["audio.Channel"]()
|
|
user = factories["users.User"]()
|
|
data = {
|
|
"channel": channel.uuid,
|
|
"audio_file": uploaded_audio_file,
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
assert serializer.is_valid() is False
|
|
assert "channel" in serializer.errors
|
|
|
|
|
|
def test_upload_with_not_owned_library_fails(factories, uploaded_audio_file):
|
|
library = factories["music.Library"]()
|
|
user = factories["users.User"]()
|
|
data = {
|
|
"library": library.uuid,
|
|
"audio_file": uploaded_audio_file,
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
assert serializer.is_valid() is False
|
|
assert "library" in serializer.errors
|
|
|
|
|
|
def test_upload_requires_library_or_channel(factories, uploaded_audio_file):
|
|
user = factories["users.User"]()
|
|
data = {
|
|
"audio_file": uploaded_audio_file,
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
|
|
with pytest.raises(
|
|
serializers.serializers.ValidationError,
|
|
match=r"You need to specify a channel or a library",
|
|
):
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
|
|
def test_upload_requires_library_or_channel_but_not_both(
|
|
factories, uploaded_audio_file
|
|
):
|
|
channel = factories["audio.Channel"](attributed_to__local=True)
|
|
library = channel.library
|
|
user = channel.attributed_to.user
|
|
data = {
|
|
"audio_file": uploaded_audio_file,
|
|
"library": library.uuid,
|
|
"channel": channel.uuid,
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
with pytest.raises(
|
|
serializers.serializers.ValidationError,
|
|
match=r"You may specify a channel or a library, not both",
|
|
):
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
|
|
def test_upload_import_metadata_serializer_simple():
|
|
serializer = serializers.ImportMetadataSerializer(data={"title": "hello"})
|
|
|
|
assert serializer.is_valid(raise_exception=True) is True
|
|
assert serializer.validated_data == {"title": "hello"}
|
|
|
|
|
|
def test_upload_import_metadata_serializer_full():
|
|
licenses.load(licenses.LICENSES)
|
|
data = {
|
|
"title": "hello",
|
|
"mbid": "3220fd02-5237-4952-8394-b7e64b0204a6",
|
|
"tags": ["politics", "gender"],
|
|
"license": "cc-by-sa-4.0",
|
|
"copyright": "My work",
|
|
"position": 42,
|
|
}
|
|
expected = data.copy()
|
|
expected["license"] = models.License.objects.get(code=data["license"])
|
|
expected["mbid"] = uuid.UUID(data["mbid"])
|
|
serializer = serializers.ImportMetadataSerializer(data=data)
|
|
|
|
assert serializer.is_valid(raise_exception=True) is True
|
|
assert serializer.validated_data == expected
|
|
|
|
|
|
def test_upload_import_metadata_serializer_channel_checks_owned_album(factories):
|
|
channel = factories["audio.Channel"]()
|
|
album = factories["music.Album"]()
|
|
data = {"title": "hello", "album": album.pk}
|
|
serializer = serializers.ImportMetadataSerializer(
|
|
data=data, context={"channel": channel}
|
|
)
|
|
|
|
with pytest.raises(serializers.serializers.ValidationError):
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
|
|
def test_upload_with_channel_keeps_import_metadata(factories, uploaded_audio_file):
|
|
channel = factories["audio.Channel"](attributed_to__local=True)
|
|
user = channel.attributed_to.user
|
|
data = {
|
|
"channel": channel.uuid,
|
|
"audio_file": uploaded_audio_file,
|
|
"import_metadata": {"title": "hello"},
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
assert serializer.is_valid(raise_exception=True) is True
|
|
upload = serializer.save()
|
|
|
|
assert upload.import_metadata == data["import_metadata"]
|
|
|
|
|
|
def test_upload_with_channel_validates_import_metadata(factories, uploaded_audio_file):
|
|
channel = factories["audio.Channel"](attributed_to__local=True)
|
|
user = channel.attributed_to.user
|
|
data = {
|
|
"channel": channel.uuid,
|
|
"audio_file": uploaded_audio_file,
|
|
"import_metadata": {"title": None},
|
|
}
|
|
serializer = serializers.UploadForOwnerSerializer(
|
|
data=data,
|
|
context={"user": user},
|
|
)
|
|
with pytest.raises(serializers.serializers.ValidationError):
|
|
assert serializer.is_valid(raise_exception=True)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"factory_name, serializer_class",
|
|
[
|
|
("music.Artist", serializers.ArtistWithAlbumsSerializer),
|
|
("music.Album", serializers.AlbumSerializer),
|
|
("music.Track", serializers.TrackSerializer),
|
|
],
|
|
)
|
|
def test_detail_serializers_with_description_description(
|
|
factory_name, serializer_class, factories
|
|
):
|
|
content = factories["common.Content"]()
|
|
obj = factories[factory_name](description=content)
|
|
expected = common_serializers.ContentSerializer(content).data
|
|
serializer = serializer_class(obj, context={"description": True})
|
|
assert serializer.data["description"] == expected
|
|
|
|
|
|
def test_sort_uploads_for_listen(factories):
|
|
local_upload = factories["music.Upload"](library__local=True)
|
|
new_local_upload = factories["music.Upload"](library__local=True)
|
|
remote_upload = factories["music.Upload"](audio_file__from_path=None)
|
|
remote_upload_with_local_version = factories["music.Upload"]()
|
|
|
|
unsorted = [
|
|
remote_upload_with_local_version,
|
|
new_local_upload,
|
|
remote_upload,
|
|
local_upload,
|
|
]
|
|
expected = [
|
|
local_upload,
|
|
new_local_upload,
|
|
remote_upload,
|
|
remote_upload_with_local_version,
|
|
]
|
|
assert serializers.sort_uploads_for_listen(unsorted) == expected
|
|
|
|
|
|
def test_album_serializer_includes_duration(tmpfile, factories):
|
|
album = factories["music.Album"]()
|
|
event = {
|
|
"path": tmpfile.name,
|
|
}
|
|
library = factories["music.Library"]()
|
|
track1 = factories["music.Track"](album=album)
|
|
track2 = factories["music.Track"](album=album)
|
|
factories["music.Upload"](
|
|
source="file://{}".format(event["path"]),
|
|
track=track1,
|
|
checksum="old",
|
|
library=library,
|
|
import_status="finished",
|
|
audio_file=None,
|
|
duration=21,
|
|
)
|
|
factories["music.Upload"](
|
|
source="file://{}".format(event["path"]),
|
|
track=track1,
|
|
checksum="old",
|
|
library=library,
|
|
import_status="finished",
|
|
audio_file=None,
|
|
duration=21,
|
|
)
|
|
factories["music.Upload"](
|
|
source="file://{}".format(event["path"]),
|
|
track=track2,
|
|
checksum="old",
|
|
library=library,
|
|
import_status="finished",
|
|
audio_file=None,
|
|
duration=21,
|
|
)
|
|
qs = album.__class__.objects.with_duration()
|
|
|
|
serializer = serializers.AlbumSerializer(qs.get())
|
|
assert serializer.data["duration"] == 42
|