test_serializers.py 10.2 KB
Newer Older
1 2
import pytest

3
from funkwhale_api.music import models
4
from funkwhale_api.music import serializers
5
from funkwhale_api.music import tasks
6 7 8


def test_artist_album_serializer(factories, to_api_date):
Eliot Berriot's avatar
Eliot Berriot committed
9
    track = factories["music.Track"]()
10 11 12
    album = track.album
    album = album.__class__.objects.with_tracks_count().get(pk=album.pk)
    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
13 14 15 16 17 18
        "id": album.id,
        "mbid": str(album.mbid),
        "title": album.title,
        "artist": album.artist.id,
        "creation_date": to_api_date(album.creation_date),
        "tracks_count": 1,
19
        "is_playable": None,
20 21 22 23 24 25
        "cover": {
            "original": album.cover.url,
            "square_crop": album.cover.crop["400x400"].url,
            "medium_square_crop": album.cover.crop["200x200"].url,
            "small_square_crop": album.cover.crop["50x50"].url,
        },
Eliot Berriot's avatar
Eliot Berriot committed
26
        "release_date": to_api_date(album.release_date),
27 28 29 30 31 32 33
    }
    serializer = serializers.ArtistAlbumSerializer(album)

    assert serializer.data == expected


def test_artist_with_albums_serializer(factories, to_api_date):
Eliot Berriot's avatar
Eliot Berriot committed
34
    track = factories["music.Track"]()
35 36 37 38 39
    artist = track.artist
    artist = artist.__class__.objects.with_albums().get(pk=artist.pk)
    album = list(artist.albums.all())[0]

    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
40 41 42 43 44
        "id": artist.id,
        "mbid": str(artist.mbid),
        "name": artist.name,
        "creation_date": to_api_date(artist.creation_date),
        "albums": [serializers.ArtistAlbumSerializer(album).data],
45 46 47 48 49 50
    }
    serializer = serializers.ArtistWithAlbumsSerializer(artist)
    assert serializer.data == expected


def test_album_track_serializer(factories, to_api_date):
Eliot Berriot's avatar
Eliot Berriot committed
51 52
    upload = factories["music.Upload"]()
    track = upload.track
53
    setattr(track, "playable_uploads", [upload])
54 55

    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
56
        "id": track.id,
57
        "artist": serializers.ArtistSimpleSerializer(track.artist).data,
Eliot Berriot's avatar
Eliot Berriot committed
58 59 60 61
        "album": track.album.id,
        "mbid": str(track.mbid),
        "title": track.title,
        "position": track.position,
62
        "uploads": [serializers.TrackUploadSerializer(upload).data],
Eliot Berriot's avatar
Eliot Berriot committed
63
        "creation_date": to_api_date(track.creation_date),
64
        "listen_url": track.listen_url,
Eliot Berriot's avatar
Eliot Berriot committed
65
        "duration": None,
66 67 68 69 70
    }
    serializer = serializers.AlbumTrackSerializer(track)
    assert serializer.data == expected


Eliot Berriot's avatar
Eliot Berriot committed
71 72
def test_upload_serializer(factories, to_api_date):
    upload = factories["music.Upload"]()
73 74

    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
75 76 77 78 79 80 81 82 83
        "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": upload.creation_date.isoformat().split("+")[0] + "Z",
84 85
        "import_date": None,
        "import_status": "pending",
86
    }
Eliot Berriot's avatar
Eliot Berriot committed
87
    serializer = serializers.UploadSerializer(upload)
88 89 90
    assert serializer.data == expected


Eliot Berriot's avatar
Eliot Berriot committed
91 92
def test_upload_owner_serializer(factories, to_api_date):
    upload = factories["music.Upload"](
93 94 95 96 97 98 99 100 101
        import_status="success",
        import_details={"hello": "world"},
        import_metadata={"import": "metadata"},
        import_reference="ref",
        metadata={"test": "metadata"},
        source="upload://test",
    )

    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
102 103 104 105 106 107 108 109 110
        "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": upload.creation_date.isoformat().split("+")[0] + "Z",
111 112 113 114 115 116 117 118
        "metadata": {"test": "metadata"},
        "import_metadata": {"import": "metadata"},
        "import_date": None,
        "import_status": "success",
        "import_details": {"hello": "world"},
        "source": "upload://test",
        "import_reference": "ref",
    }
Eliot Berriot's avatar
Eliot Berriot committed
119
    serializer = serializers.UploadForOwnerSerializer(upload)
120 121 122
    assert serializer.data == expected


123
def test_album_serializer(factories, to_api_date):
Eliot Berriot's avatar
Eliot Berriot committed
124 125
    track1 = factories["music.Track"](position=2)
    track2 = factories["music.Track"](position=1, album=track1.album)
126 127
    album = track1.album
    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
128 129 130 131 132
        "id": album.id,
        "mbid": str(album.mbid),
        "title": album.title,
        "artist": serializers.ArtistSimpleSerializer(album.artist).data,
        "creation_date": to_api_date(album.creation_date),
133
        "is_playable": False,
134 135 136 137 138 139
        "cover": {
            "original": album.cover.url,
            "square_crop": album.cover.crop["400x400"].url,
            "medium_square_crop": album.cover.crop["200x200"].url,
            "small_square_crop": album.cover.crop["50x50"].url,
        },
Eliot Berriot's avatar
Eliot Berriot committed
140 141
        "release_date": to_api_date(album.release_date),
        "tracks": serializers.AlbumTrackSerializer([track2, track1], many=True).data,
142 143 144 145 146 147 148
    }
    serializer = serializers.AlbumSerializer(album)

    assert serializer.data == expected


def test_track_serializer(factories, to_api_date):
Eliot Berriot's avatar
Eliot Berriot committed
149 150
    upload = factories["music.Upload"]()
    track = upload.track
151
    setattr(track, "playable_uploads", [upload])
152
    expected = {
Eliot Berriot's avatar
Eliot Berriot committed
153 154 155 156 157 158
        "id": track.id,
        "artist": serializers.ArtistSimpleSerializer(track.artist).data,
        "album": serializers.TrackAlbumSerializer(track.album).data,
        "mbid": str(track.mbid),
        "title": track.title,
        "position": track.position,
159
        "uploads": [serializers.TrackUploadSerializer(upload).data],
Eliot Berriot's avatar
Eliot Berriot committed
160 161
        "creation_date": to_api_date(track.creation_date),
        "lyrics": track.get_lyrics_url(),
162
        "listen_url": track.listen_url,
163 164 165
    }
    serializer = serializers.TrackSerializer(track)
    assert serializer.data == expected
166 167 168 169 170 171


def test_user_cannot_bind_file_to_a_not_owned_library(factories):
    user = factories["users.User"]()
    library = factories["music.Library"]()

Eliot Berriot's avatar
Eliot Berriot committed
172
    s = serializers.UploadForOwnerSerializer(
173 174 175 176 177 178 179 180 181 182
        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)
Eliot Berriot's avatar
Eliot Berriot committed
183
    s = serializers.UploadForOwnerSerializer(
184 185 186 187 188 189 190 191
        data={
            "library": library.uuid,
            "source": "upload://test",
            "audio_file": uploaded_audio_file,
        },
        context={"user": user},
    )
    assert s.is_valid(raise_exception=True) is True
Eliot Berriot's avatar
Eliot Berriot committed
192
    upload = s.save()
193

Eliot Berriot's avatar
Eliot Berriot committed
194
    assert upload.library == library
195 196 197 198 199 200 201 202 203 204 205


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)
Eliot Berriot's avatar
Eliot Berriot committed
206
    s = serializers.UploadForOwnerSerializer(
207 208 209 210 211 212 213 214 215 216 217
        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"]


Eliot Berriot's avatar
Eliot Berriot committed
218 219 220 221 222 223 224
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)
225

Eliot Berriot's avatar
Eliot Berriot committed
226
    s.handle_delete(library1_uploads[0].__class__.objects.all())
227

Eliot Berriot's avatar
Eliot Berriot committed
228 229 230 231 232 233 234 235 236
    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},
    )
237 238


Eliot Berriot's avatar
Eliot Berriot committed
239
def test_manage_upload_action_relaunch_import(factories, mocker):
240 241 242
    m = mocker.patch("funkwhale_api.common.utils.on_commit")

    # this one is finished and should stay as is
Eliot Berriot's avatar
Eliot Berriot committed
243
    finished = factories["music.Upload"](import_status="finished")
244 245

    to_relaunch = [
Eliot Berriot's avatar
Eliot Berriot committed
246 247 248
        factories["music.Upload"](import_status="pending"),
        factories["music.Upload"](import_status="skipped"),
        factories["music.Upload"](import_status="errored"),
249
    ]
Eliot Berriot's avatar
Eliot Berriot committed
250
    s = serializers.UploadActionSerializer(queryset=None)
251

Eliot Berriot's avatar
Eliot Berriot committed
252
    s.handle_relaunch_import(models.Upload.objects.all())
253 254 255 256

    for obj in to_relaunch:
        obj.refresh_from_db()
        assert obj.import_status == "pending"
257
        m.assert_any_call(tasks.process_upload.delay, upload_id=obj.pk)
258 259 260 261

    finished.refresh_from_db()
    assert finished.import_status == "finished"
    assert m.call_count == 3
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278


def test_track_upload_serializer(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,
    }

    serializer = serializers.TrackUploadSerializer(upload)
    assert serializer.data == expected
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303


@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}
    )