import json import pytest from django.urls import reverse from funkwhale_api.federation import actors from funkwhale_api.federation import serializers as federation_serializers from funkwhale_api.music import tasks def test_create_import_can_bind_to_request( artists, albums, mocker, factories, superuser_api_client): request = factories['requests.ImportRequest']() mocker.patch('funkwhale_api.music.tasks.import_job_run') mocker.patch( 'funkwhale_api.musicbrainz.api.artists.get', return_value=artists['get']['soad']) mocker.patch( 'funkwhale_api.musicbrainz.api.images.get_front', return_value=b'') mocker.patch( 'funkwhale_api.musicbrainz.api.releases.get', return_value=albums['get_with_includes']['hypnotize']) payload = { 'releaseId': '47ae093f-1607-49a3-be11-a15d335ccc94', 'importRequest': request.pk, 'tracks': [ { 'mbid': '1968a9d6-8d92-4051-8f76-674e157b6eed', 'source': 'https://www.youtube.com/watch?v=1111111111', } ] } url = reverse('api:v1:submit-album') response = superuser_api_client.post( url, json.dumps(payload), content_type='application/json') batch = request.import_batches.latest('id') assert batch.import_request == request def test_import_job_from_federation_no_musicbrainz(factories): lt = factories['federation.LibraryTrack']( artist_name='Hello', album_title='World', title='Ping', ) job = factories['music.ImportJob']( federation=True, library_track=lt, ) tasks.import_job_run(import_job_id=job.pk) job.refresh_from_db() tf = job.track_file assert tf.mimetype == lt.audio_mimetype assert tf.library_track == job.library_track assert tf.track.title == 'Ping' assert tf.track.artist.name == 'Hello' assert tf.track.album.title == 'World' def test_import_job_from_federation_musicbrainz_recording(factories, mocker): t = factories['music.Track']() track_from_api = mocker.patch( 'funkwhale_api.music.models.Track.get_or_create_from_api', return_value=t) lt = factories['federation.LibraryTrack']( metadata__recording__musicbrainz=True, artist_name='Hello', album_title='World', ) job = factories['music.ImportJob']( federation=True, library_track=lt, ) tasks.import_job_run(import_job_id=job.pk) job.refresh_from_db() tf = job.track_file assert tf.mimetype == lt.audio_mimetype assert tf.library_track == job.library_track assert tf.track == t track_from_api.assert_called_once_with( mbid=lt.metadata['recording']['musicbrainz_id']) def test_import_job_from_federation_musicbrainz_release(factories, mocker): a = factories['music.Album']() album_from_api = mocker.patch( 'funkwhale_api.music.models.Album.get_or_create_from_api', return_value=a) lt = factories['federation.LibraryTrack']( metadata__release__musicbrainz=True, artist_name='Hello', title='Ping', ) job = factories['music.ImportJob']( federation=True, library_track=lt, ) tasks.import_job_run(import_job_id=job.pk) job.refresh_from_db() tf = job.track_file assert tf.mimetype == lt.audio_mimetype assert tf.library_track == job.library_track assert tf.track.title == 'Ping' assert tf.track.artist == a.artist assert tf.track.album == a album_from_api.assert_called_once_with( mbid=lt.metadata['release']['musicbrainz_id']) def test_import_job_from_federation_musicbrainz_artist(factories, mocker): a = factories['music.Artist']() artist_from_api = mocker.patch( 'funkwhale_api.music.models.Artist.get_or_create_from_api', return_value=a) lt = factories['federation.LibraryTrack']( metadata__artist__musicbrainz=True, album_title='World', title='Ping', ) job = factories['music.ImportJob']( federation=True, library_track=lt, ) tasks.import_job_run(import_job_id=job.pk) job.refresh_from_db() tf = job.track_file assert tf.mimetype == lt.audio_mimetype assert tf.library_track == job.library_track assert tf.track.title == 'Ping' assert tf.track.artist == a assert tf.track.album.artist == a assert tf.track.album.title == 'World' artist_from_api.assert_called_once_with( mbid=lt.metadata['artist']['musicbrainz_id']) def test_import_job_run_triggers_notifies_followers( factories, mocker, tmpfile): mocker.patch( 'funkwhale_api.downloader.download', return_value={'audio_file_path': tmpfile.name}) mocked_notify = mocker.patch( 'funkwhale_api.music.tasks.import_batch_notify_followers.delay') batch = factories['music.ImportBatch']() job = factories['music.ImportJob']( finished=True, batch=batch) track = factories['music.Track'](mbid=job.mbid) batch.update_status() batch.refresh_from_db() assert batch.status == 'finished' mocked_notify.assert_called_once_with(import_batch_id=batch.pk) def test_import_batch_notifies_followers_skip_on_disabled_federation( settings, factories, mocker): mocked_deliver = mocker.patch('funkwhale_api.federation.activity.deliver') batch = factories['music.ImportBatch'](finished=True) settings.FEDERATION_ENABLED = False tasks.import_batch_notify_followers(import_batch_id=batch.pk) mocked_deliver.assert_not_called() def test_import_batch_notifies_followers_skip_on_federation_import( factories, mocker): mocked_deliver = mocker.patch('funkwhale_api.federation.activity.deliver') batch = factories['music.ImportBatch'](finished=True, federation=True) tasks.import_batch_notify_followers(import_batch_id=batch.pk) mocked_deliver.assert_not_called() def test_import_batch_notifies_followers( factories, mocker): library_actor = actors.SYSTEM_ACTORS['library'].get_actor_instance() f1 = factories['federation.Follow'](approved=True, target=library_actor) f2 = factories['federation.Follow'](approved=False, target=library_actor) f3 = factories['federation.Follow']() mocked_deliver = mocker.patch('funkwhale_api.federation.activity.deliver') batch = factories['music.ImportBatch']() job1 = factories['music.ImportJob']( finished=True, batch=batch) job2 = factories['music.ImportJob']( finished=True, federation=True, batch=batch) job3 = factories['music.ImportJob']( status='pending', batch=batch) batch.status = 'finished' batch.save() tasks.import_batch_notify_followers(import_batch_id=batch.pk) # only f1 match the requirements to be notified # and only job1 is a non federated track with finished import expected = { '@context': federation_serializers.AP_CONTEXT, 'actor': library_actor.url, 'type': 'Create', 'id': batch.get_federation_url(), 'to': [f1.actor.url], 'object': federation_serializers.CollectionSerializer( { 'id': batch.get_federation_url(), 'items': [job1.track_file], 'actor': library_actor, 'item_serializer': federation_serializers.AudioSerializer } ).data } mocked_deliver.assert_called_once_with( expected, on_behalf_of=library_actor, to=[f1.actor.url] ) def test__do_import_in_place_mbid(factories, tmpfile): path = '/test.ogg' job = factories['music.ImportJob']( in_place=True, source='file:///test.ogg') track = factories['music.Track'](mbid=job.mbid) tf = tasks._do_import(job, use_acoustid=False) assert bool(tf.audio_file) is False assert tf.source == 'file:///test.ogg'