Fixed #54: Now use pytest everywhere \o/

merge-requests/154/head
Eliot Berriot 2017-12-24 19:15:21 +01:00
rodzic a7758395ee
commit 099cdfa99c
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: DD6965E2476E5C27
65 zmienionych plików z 1466 dodań i 1467 usunięć

Wyświetl plik

@ -1,32 +0,0 @@
from test_plus.test import TestCase
from rest_framework_jwt.settings import api_settings
from funkwhale_api.users.models import User
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class TestJWTQueryString(TestCase):
www_authenticate_realm = 'api'
def test_can_authenticate_using_token_param_in_url(self):
user = User.objects.create_superuser(
username='test', email='test@test.com', password='test')
url = self.reverse('api:v1:tracks-list')
with self.settings(API_AUTHENTICATION_REQUIRED=True):
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
print(payload, token)
with self.settings(API_AUTHENTICATION_REQUIRED=True):
response = self.client.get(url, data={
'jwt': token
})
self.assertEqual(response.status_code, 200)

Wyświetl plik

@ -1,14 +0,0 @@
import os
from test_plus.test import TestCase
from .. import downloader
from funkwhale_api.utils.tests import TMPDirTestCaseMixin
class TestDownloader(TMPDirTestCaseMixin, TestCase):
def test_can_download_audio_from_youtube_url_to_vorbis(self):
data = downloader.download('https://www.youtube.com/watch?v=tPEE9ZwTmy0', target_directory=self.download_dir)
self.assertEqual(
data['audio_file_path'],
os.path.join(self.download_dir, 'tPEE9ZwTmy0.ogg'))
self.assertTrue(os.path.exists(data['audio_file_path']))

Wyświetl plik

@ -0,0 +1,30 @@
import factory
import persisting_theory
class FactoriesRegistry(persisting_theory.Registry):
look_into = 'factories'
def prepare_name(self, data, name=None):
return name or data._meta.model._meta.label
registry = FactoriesRegistry()
def ManyToManyFromList(field_name):
"""
To automate the pattern described in
http://factoryboy.readthedocs.io/en/latest/recipes.html#simple-many-to-many-relationship
"""
@factory.post_generation
def inner(self, create, extracted, **kwargs):
if not create:
return
if extracted:
field = getattr(self, field_name)
field.add(*extracted)
return inner

Wyświetl plik

@ -0,0 +1,15 @@
import factory
from funkwhale_api.factories import registry
from funkwhale_api.music.factories import TrackFactory
from funkwhale_api.users.factories import UserFactory
@registry.register
class TrackFavorite(factory.django.DjangoModelFactory):
track = factory.SubFactory(TrackFactory)
user = factory.SubFactory(UserFactory)
class Meta:
model = 'favorites.TrackFavorite'

Wyświetl plik

@ -1,113 +0,0 @@
import json
from test_plus.test import TestCase
from django.urls import reverse
from funkwhale_api.music.models import Track, Artist
from funkwhale_api.favorites.models import TrackFavorite
from funkwhale_api.users.models import User
class TestFavorites(TestCase):
def setUp(self):
super().setUp()
self.artist = Artist.objects.create(name='test')
self.track = Track.objects.create(title='test', artist=self.artist)
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_user_can_add_favorite(self):
TrackFavorite.add(self.track, self.user)
favorite = TrackFavorite.objects.latest('id')
self.assertEqual(favorite.track, self.track)
self.assertEqual(favorite.user, self.user)
def test_user_can_get_his_favorites(self):
favorite = TrackFavorite.add(self.track, self.user)
url = reverse('api:v1:favorites:tracks-list')
self.client.login(username=self.user.username, password='test')
response = self.client.get(url)
expected = [
{
'track': self.track.pk,
'id': favorite.id,
'creation_date': favorite.creation_date.isoformat().replace('+00:00', 'Z'),
}
]
parsed_json = json.loads(response.content.decode('utf-8'))
self.assertEqual(expected, parsed_json['results'])
def test_user_can_add_favorite_via_api(self):
url = reverse('api:v1:favorites:tracks-list')
self.client.login(username=self.user.username, password='test')
response = self.client.post(url, {'track': self.track.pk})
favorite = TrackFavorite.objects.latest('id')
expected = {
'track': self.track.pk,
'id': favorite.id,
'creation_date': favorite.creation_date.isoformat().replace('+00:00', 'Z'),
}
parsed_json = json.loads(response.content.decode('utf-8'))
self.assertEqual(expected, parsed_json)
self.assertEqual(favorite.track, self.track)
self.assertEqual(favorite.user, self.user)
def test_user_can_remove_favorite_via_api(self):
favorite = TrackFavorite.add(self.track, self.user)
url = reverse('api:v1:favorites:tracks-detail', kwargs={'pk': favorite.pk})
self.client.login(username=self.user.username, password='test')
response = self.client.delete(url, {'track': self.track.pk})
self.assertEqual(response.status_code, 204)
self.assertEqual(TrackFavorite.objects.count(), 0)
def test_user_can_remove_favorite_via_api_using_track_id(self):
favorite = TrackFavorite.add(self.track, self.user)
url = reverse('api:v1:favorites:tracks-remove')
self.client.login(username=self.user.username, password='test')
response = self.client.delete(
url, json.dumps({'track': self.track.pk}),
content_type='application/json'
)
self.assertEqual(response.status_code, 204)
self.assertEqual(TrackFavorite.objects.count(), 0)
from funkwhale_api.users.models import User
def test_can_restrict_api_views_to_authenticated_users(self):
urls = [
('api:v1:favorites:tracks-list', 'get'),
]
for route_name, method in urls:
url = self.reverse(route_name)
with self.settings(API_AUTHENTICATION_REQUIRED=True):
response = getattr(self.client, method)(url)
self.assertEqual(response.status_code, 401)
self.client.login(username=self.user.username, password='test')
for route_name, method in urls:
url = self.reverse(route_name)
with self.settings(API_AUTHENTICATION_REQUIRED=False):
response = getattr(self.client, method)(url)
self.assertEqual(response.status_code, 200)
def test_can_filter_tracks_by_favorites(self):
favorite = TrackFavorite.add(self.track, self.user)
url = reverse('api:v1:tracks-list')
self.client.login(username=self.user.username, password='test')
response = self.client.get(url, data={'favorites': True})
parsed_json = json.loads(response.content.decode('utf-8'))
self.assertEqual(parsed_json['count'], 1)
self.assertEqual(parsed_json['results'][0]['id'], self.track.id)

Wyświetl plik

@ -1,9 +1,11 @@
import factory
from funkwhale_api.music.tests import factories
from funkwhale_api.users.tests.factories import UserFactory
from funkwhale_api.factories import registry
from funkwhale_api.music import factories
from funkwhale_api.users.factories import UserFactory
@registry.register
class ListeningFactory(factory.django.DjangoModelFactory):
user = factory.SubFactory(UserFactory)
track = factory.SubFactory(factories.TrackFactory)

Wyświetl plik

@ -1,50 +0,0 @@
import random
import json
from test_plus.test import TestCase
from django.urls import reverse
from django.core.exceptions import ValidationError
from django.utils import timezone
from funkwhale_api.music.tests.factories import TrackFactory
from funkwhale_api.users.models import User
from funkwhale_api.history import models
class TestHistory(TestCase):
def setUp(self):
super().setUp()
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_can_create_listening(self):
track = TrackFactory()
now = timezone.now()
l = models.Listening.objects.create(user=self.user, track=track)
def test_anonymous_user_can_create_listening_via_api(self):
track = TrackFactory()
url = self.reverse('api:v1:history:listenings-list')
response = self.client.post(url, {
'track': track.pk,
})
listening = models.Listening.objects.latest('id')
self.assertEqual(listening.track, track)
self.assertIsNotNone(listening.session_key)
def test_logged_in_user_can_create_listening_via_api(self):
track = TrackFactory()
self.client.login(username=self.user.username, password='test')
url = self.reverse('api:v1:history:listenings-list')
response = self.client.post(url, {
'track': track.pk,
})
listening = models.Listening.objects.latest('id')
self.assertEqual(listening.track, track)
self.assertEqual(listening.user, self.user)

Wyświetl plik

@ -1,11 +1,16 @@
import factory
import os
from funkwhale_api.users.tests.factories import UserFactory
from funkwhale_api.factories import registry, ManyToManyFromList
from funkwhale_api.users.factories import UserFactory
SAMPLES_PATH = os.path.dirname(os.path.abspath(__file__))
SAMPLES_PATH = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
'tests', 'music'
)
@registry.register
class ArtistFactory(factory.django.DjangoModelFactory):
name = factory.Faker('name')
mbid = factory.Faker('uuid4')
@ -14,6 +19,7 @@ class ArtistFactory(factory.django.DjangoModelFactory):
model = 'music.Artist'
@registry.register
class AlbumFactory(factory.django.DjangoModelFactory):
title = factory.Faker('sentence', nb_words=3)
mbid = factory.Faker('uuid4')
@ -26,17 +32,19 @@ class AlbumFactory(factory.django.DjangoModelFactory):
model = 'music.Album'
@registry.register
class TrackFactory(factory.django.DjangoModelFactory):
title = factory.Faker('sentence', nb_words=3)
mbid = factory.Faker('uuid4')
album = factory.SubFactory(AlbumFactory)
artist = factory.SelfAttribute('album.artist')
position = 1
tags = ManyToManyFromList('tags')
class Meta:
model = 'music.Track'
@registry.register
class TrackFileFactory(factory.django.DjangoModelFactory):
track = factory.SubFactory(TrackFactory)
audio_file = factory.django.FileField(
@ -46,6 +54,7 @@ class TrackFileFactory(factory.django.DjangoModelFactory):
model = 'music.TrackFile'
@registry.register
class ImportBatchFactory(factory.django.DjangoModelFactory):
submitted_by = factory.SubFactory(UserFactory)
@ -53,14 +62,17 @@ class ImportBatchFactory(factory.django.DjangoModelFactory):
model = 'music.ImportBatch'
@registry.register
class ImportJobFactory(factory.django.DjangoModelFactory):
batch = factory.SubFactory(ImportBatchFactory)
source = factory.Faker('url')
mbid = factory.Faker('uuid4')
class Meta:
model = 'music.ImportJob'
@registry.register
class WorkFactory(factory.django.DjangoModelFactory):
mbid = factory.Faker('uuid4')
language = 'eng'
@ -71,6 +83,7 @@ class WorkFactory(factory.django.DjangoModelFactory):
model = 'music.Work'
@registry.register
class LyricsFactory(factory.django.DjangoModelFactory):
work = factory.SubFactory(WorkFactory)
url = factory.Faker('url')
@ -80,6 +93,7 @@ class LyricsFactory(factory.django.DjangoModelFactory):
model = 'music.Lyrics'
@registry.register
class TagFactory(factory.django.DjangoModelFactory):
name = factory.SelfAttribute('slug')
slug = factory.Faker('slug')

Wyświetl plik

@ -1,256 +0,0 @@
import json
import unittest
from test_plus.test import TestCase
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.utils.tests import TMPDirTestCaseMixin
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from funkwhale_api.users.models import User
from . import data as api_data
from . import factories
class TestAPI(TMPDirTestCaseMixin, TestCase):
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['adhesive_wombat'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.get', return_value=api_data.albums['get']['marsupial'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.get', return_value=api_data.tracks['get']['8bitadventures'])
@unittest.mock.patch('funkwhale_api.music.models.TrackFile.download_file', return_value=None)
def test_can_submit_youtube_url_for_track_import(self, *mocks):
mbid = '9968a9d6-8d92-4051-8f76-674e157b6eed'
video_id = 'tPEE9ZwTmy0'
url = reverse('api:v1:submit-single')
user = User.objects.create_superuser(username='test', email='test@test.com', password='test')
self.client.login(username=user.username, password='test')
response = self.client.post(url, {'import_url': 'https://www.youtube.com/watch?v={0}'.format(video_id), 'mbid': mbid})
track = models.Track.objects.get(mbid=mbid)
self.assertEqual(track.artist.name, 'Adhesive Wombat')
self.assertEqual(track.album.title, 'Marsupial Madness')
# self.assertIn(video_id, track.files.first().audio_file.name)
def test_import_creates_an_import_with_correct_data(self):
user = User.objects.create_superuser(username='test', email='test@test.com', password='test')
mbid = '9968a9d6-8d92-4051-8f76-674e157b6eed'
video_id = 'tPEE9ZwTmy0'
url = reverse('api:v1:submit-single')
self.client.login(username=user.username, password='test')
with self.settings(CELERY_ALWAYS_EAGER=False):
response = self.client.post(url, {'import_url': 'https://www.youtube.com/watch?v={0}'.format(video_id), 'mbid': mbid})
batch = models.ImportBatch.objects.latest('id')
self.assertEqual(batch.jobs.count(), 1)
self.assertEqual(batch.submitted_by, user)
self.assertEqual(batch.status, 'pending')
job = batch.jobs.first()
self.assertEqual(str(job.mbid), mbid)
self.assertEqual(job.status, 'pending')
self.assertEqual(job.source, 'https://www.youtube.com/watch?v={0}'.format(video_id))
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['soad'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.images.get_front', return_value=b'')
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.get', return_value=api_data.albums['get_with_includes']['hypnotize'])
def test_can_import_whole_album(self, *mocks):
user = User.objects.create_superuser(username='test', email='test@test.com', password='test')
payload = {
'releaseId': '47ae093f-1607-49a3-be11-a15d335ccc94',
'tracks': [
{
'mbid': '1968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=1111111111',
},
{
'mbid': '2968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=2222222222',
},
{
'mbid': '3968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=3333333333',
},
]
}
url = reverse('api:v1:submit-album')
self.client.login(username=user.username, password='test')
with self.settings(CELERY_ALWAYS_EAGER=False):
response = self.client.post(url, json.dumps(payload), content_type="application/json")
batch = models.ImportBatch.objects.latest('id')
self.assertEqual(batch.jobs.count(), 3)
self.assertEqual(batch.submitted_by, user)
self.assertEqual(batch.status, 'pending')
album = models.Album.objects.latest('id')
self.assertEqual(str(album.mbid), '47ae093f-1607-49a3-be11-a15d335ccc94')
medium_data = api_data.albums['get_with_includes']['hypnotize']['release']['medium-list'][0]
self.assertEqual(int(medium_data['track-count']), album.tracks.all().count())
for track in medium_data['track-list']:
instance = models.Track.objects.get(mbid=track['recording']['id'])
self.assertEqual(instance.title, track['recording']['title'])
self.assertEqual(instance.position, int(track['position']))
self.assertEqual(instance.title, track['recording']['title'])
for row in payload['tracks']:
job = models.ImportJob.objects.get(mbid=row['mbid'])
self.assertEqual(str(job.mbid), row['mbid'])
self.assertEqual(job.status, 'pending')
self.assertEqual(job.source, row['source'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['soad'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.images.get_front', return_value=b'')
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.get', return_value=api_data.albums['get_with_includes']['hypnotize'])
def test_can_import_whole_artist(self, *mocks):
user = User.objects.create_superuser(username='test', email='test@test.com', password='test')
payload = {
'artistId': 'mbid',
'albums': [
{
'releaseId': '47ae093f-1607-49a3-be11-a15d335ccc94',
'tracks': [
{
'mbid': '1968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=1111111111',
},
{
'mbid': '2968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=2222222222',
},
{
'mbid': '3968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=3333333333',
},
]
}
]
}
url = reverse('api:v1:submit-artist')
self.client.login(username=user.username, password='test')
with self.settings(CELERY_ALWAYS_EAGER=False):
response = self.client.post(url, json.dumps(payload), content_type="application/json")
batch = models.ImportBatch.objects.latest('id')
self.assertEqual(batch.jobs.count(), 3)
self.assertEqual(batch.submitted_by, user)
self.assertEqual(batch.status, 'pending')
album = models.Album.objects.latest('id')
self.assertEqual(str(album.mbid), '47ae093f-1607-49a3-be11-a15d335ccc94')
medium_data = api_data.albums['get_with_includes']['hypnotize']['release']['medium-list'][0]
self.assertEqual(int(medium_data['track-count']), album.tracks.all().count())
for track in medium_data['track-list']:
instance = models.Track.objects.get(mbid=track['recording']['id'])
self.assertEqual(instance.title, track['recording']['title'])
self.assertEqual(instance.position, int(track['position']))
self.assertEqual(instance.title, track['recording']['title'])
for row in payload['albums'][0]['tracks']:
job = models.ImportJob.objects.get(mbid=row['mbid'])
self.assertEqual(str(job.mbid), row['mbid'])
self.assertEqual(job.status, 'pending')
self.assertEqual(job.source, row['source'])
def test_user_can_query_api_for_his_own_batches(self):
user1 = User.objects.create_superuser(username='test1', email='test1@test.com', password='test')
user2 = User.objects.create_superuser(username='test2', email='test2@test.com', password='test')
mbid = '9968a9d6-8d92-4051-8f76-674e157b6eed'
source = 'https://www.youtube.com/watch?v=tPEE9ZwTmy0'
batch = models.ImportBatch.objects.create(submitted_by=user1)
job = models.ImportJob.objects.create(batch=batch, mbid=mbid, source=source)
url = reverse('api:v1:import-batches-list')
self.client.login(username=user2.username, password='test')
response2 = self.client.get(url)
self.assertJSONEqual(response2.content.decode('utf-8'), '{"count":0,"next":null,"previous":null,"results":[]}')
self.client.logout()
self.client.login(username=user1.username, password='test')
response1 = self.client.get(url)
self.assertIn(mbid, response1.content.decode('utf-8'))
def test_can_search_artist(self):
artist1 = models.Artist.objects.create(name='Test1')
artist2 = models.Artist.objects.create(name='Test2')
query = 'test1'
expected = '[{0}]'.format(json.dumps(serializers.ArtistSerializerNested(artist1).data))
url = self.reverse('api:v1:artists-search')
response = self.client.get(url + '?query={0}'.format(query))
self.assertJSONEqual(expected, json.loads(response.content.decode('utf-8')))
def test_can_search_artist_by_name_start(self):
artist1 = factories.ArtistFactory(name='alpha')
artist2 = factories.ArtistFactory(name='beta')
results = {
'next': None,
'previous': None,
'count': 1,
'results': [serializers.ArtistSerializerNested(artist1).data]
}
expected = json.dumps(results)
url = self.reverse('api:v1:artists-list')
response = self.client.get(url, {'name__startswith': 'a'})
self.assertJSONEqual(expected, json.loads(response.content.decode('utf-8')))
def test_can_search_tracks(self):
artist1 = models.Artist.objects.create(name='Test1')
artist2 = models.Artist.objects.create(name='Test2')
track1 = models.Track.objects.create(artist=artist1, title="test_track1")
track2 = models.Track.objects.create(artist=artist2, title="test_track2")
query = 'test track 1'
expected = '[{0}]'.format(json.dumps(serializers.TrackSerializerNested(track1).data))
url = self.reverse('api:v1:tracks-search')
response = self.client.get(url + '?query={0}'.format(query))
self.assertJSONEqual(expected, json.loads(response.content.decode('utf-8')))
def test_can_restrict_api_views_to_authenticated_users(self):
urls = [
('api:v1:tags-list', 'get'),
('api:v1:tracks-list', 'get'),
('api:v1:artists-list', 'get'),
('api:v1:albums-list', 'get'),
]
for route_name, method in urls:
url = self.reverse(route_name)
with self.settings(API_AUTHENTICATION_REQUIRED=True):
response = getattr(self.client, method)(url)
self.assertEqual(response.status_code, 401)
user = User.objects.create_superuser(username='test', email='test@test.com', password='test')
self.client.login(username=user.username, password='test')
for route_name, method in urls:
url = self.reverse(route_name)
with self.settings(API_AUTHENTICATION_REQUIRED=False):
response = getattr(self.client, method)(url)
self.assertEqual(response.status_code, 200)
def test_track_file_url_is_restricted_to_authenticated_users(self):
f = factories.TrackFileFactory()
self.assertNotEqual(f.audio_file, None)
url = f.path
with self.settings(API_AUTHENTICATION_REQUIRED=True):
response = self.client.get(url)
self.assertEqual(response.status_code, 401)
user = User.objects.create_superuser(
username='test', email='test@test.com', password='test')
self.client.login(username=user.username, password='test')
with self.settings(API_AUTHENTICATION_REQUIRED=True):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response['X-Accel-Redirect'],
'/_protected{}'.format(f.audio_file.url)
)

Wyświetl plik

@ -1,75 +0,0 @@
import json
import unittest
from test_plus.test import TestCase
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from funkwhale_api.users.models import User
from funkwhale_api.music import lyrics as lyrics_utils
from .mocking import lyricswiki
from . import factories
from . import data as api_data
class TestLyrics(TestCase):
@unittest.mock.patch('funkwhale_api.music.lyrics._get_html',
return_value=lyricswiki.content)
def test_works_import_lyrics_if_any(self, *mocks):
lyrics = factories.LyricsFactory(
url='http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!')
lyrics.fetch_content()
self.assertIn(
'Grab a brush and put on a little makeup',
lyrics.content,
)
def test_clean_content(self):
c = """<div class="lyricbox">Hello<br /><script>alert('hello');</script>Is it me you're looking for?<br /></div>"""
d = lyrics_utils.extract_content(c)
d = lyrics_utils.clean_content(d)
expected = """Hello
Is it me you're looking for?
"""
self.assertEqual(d, expected)
def test_markdown_rendering(self):
content = """Hello
Is it me you're looking for?"""
l = factories.LyricsFactory(content=content)
expected = "<p>Hello<br />Is it me you're looking for?</p>"
self.assertHTMLEqual(expected, l.content_rendered)
@unittest.mock.patch('funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['chop_suey'])
@unittest.mock.patch('funkwhale_api.music.lyrics._get_html',
return_value=lyricswiki.content)
def test_works_import_lyrics_if_any(self, *mocks):
track = factories.TrackFactory(
work=None,
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
url = reverse('api:v1:tracks-lyrics', kwargs={'pk': track.pk})
user = User.objects.create_user(
username='test', email='test@test.com', password='test')
self.client.login(username=user.username, password='test')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
track.refresh_from_db()
lyrics = models.Lyrics.objects.latest('id')
work = models.Work.objects.latest('id')
self.assertEqual(track.work, work)
self.assertEqual(lyrics.work, work)

Wyświetl plik

@ -1,80 +0,0 @@
import unittest
import os
import datetime
from test_plus.test import TestCase
from funkwhale_api.music import metadata
DATA_DIR = os.path.dirname(os.path.abspath(__file__))
class TestMetadata(TestCase):
def test_can_get_metadata_from_ogg_file(self, *mocks):
path = os.path.join(DATA_DIR, 'test.ogg')
data = metadata.Metadata(path)
self.assertEqual(
data.get('title'),
'Peer Gynt Suite no. 1, op. 46: I. Morning'
)
self.assertEqual(
data.get('artist'),
'Edvard Grieg'
)
self.assertEqual(
data.get('album'),
'Peer Gynt Suite no. 1, op. 46'
)
self.assertEqual(
data.get('date'),
datetime.date(2012, 8, 15),
)
self.assertEqual(
data.get('track_number'),
1
)
self.assertEqual(
data.get('musicbrainz_albumid'),
'a766da8b-8336-47aa-a3ee-371cc41ccc75')
self.assertEqual(
data.get('musicbrainz_recordingid'),
'bd21ac48-46d8-4e78-925f-d9cc2a294656')
self.assertEqual(
data.get('musicbrainz_artistid'),
'013c8e5b-d72a-4cd3-8dee-6c64d6125823')
def test_can_get_metadata_from_id3_mp3_file(self, *mocks):
path = os.path.join(DATA_DIR, 'test.mp3')
data = metadata.Metadata(path)
self.assertEqual(
data.get('title'),
'Bend'
)
self.assertEqual(
data.get('artist'),
'Binärpilot'
)
self.assertEqual(
data.get('album'),
'You Can\'t Stop Da Funk'
)
self.assertEqual(
data.get('date'),
datetime.date(2006, 2, 7),
)
self.assertEqual(
data.get('track_number'),
1
)
self.assertEqual(
data.get('musicbrainz_albumid'),
'ce40cdb1-a562-4fd8-a269-9269f98d4124')
self.assertEqual(
data.get('musicbrainz_recordingid'),
'f269d497-1cc0-4ae4-a0c4-157ec7d73fcb')
self.assertEqual(
data.get('musicbrainz_artistid'),
'9c6bddde-6228-4d9f-ad0d-03f6fcb19e13')

Wyświetl plik

@ -1,113 +0,0 @@
from test_plus.test import TestCase
import unittest.mock
from funkwhale_api.music import models
import datetime
from . import factories
from . import data as api_data
from .cover import binary_data
class TestMusic(TestCase):
@unittest.mock.patch('musicbrainzngs.search_artists', return_value=api_data.artists['search']['adhesive_wombat'])
def test_can_create_artist_from_api(self, *mocks):
artist = models.Artist.create_from_api(query="Adhesive wombat")
data = models.Artist.api.search(query='Adhesive wombat')['artist-list'][0]
self.assertEqual(int(data['ext:score']), 100)
self.assertEqual(data['id'], '62c3befb-6366-4585-b256-809472333801')
self.assertEqual(artist.mbid, data['id'])
self.assertEqual(artist.name, 'Adhesive Wombat')
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.search', return_value=api_data.albums['search']['hypnotize'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['soad'])
def test_can_create_album_from_api(self, *mocks):
album = models.Album.create_from_api(query="Hypnotize", artist='system of a down', type='album')
data = models.Album.api.search(query='Hypnotize', artist='system of a down', type='album')['release-list'][0]
self.assertEqual(album.mbid, data['id'])
self.assertEqual(album.title, 'Hypnotize')
with self.assertRaises(ValueError):
self.assertFalse(album.cover.path is None)
self.assertEqual(album.release_date, datetime.date(2005, 1, 1))
self.assertEqual(album.artist.name, 'System of a Down')
self.assertEqual(album.artist.mbid, data['artist-credit'][0]['artist']['id'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['adhesive_wombat'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.get', return_value=api_data.albums['get']['marsupial'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.search', return_value=api_data.tracks['search']['8bitadventures'])
def test_can_create_track_from_api(self, *mocks):
track = models.Track.create_from_api(query="8-bit adventure")
data = models.Track.api.search(query='8-bit adventure')['recording-list'][0]
self.assertEqual(int(data['ext:score']), 100)
self.assertEqual(data['id'], '9968a9d6-8d92-4051-8f76-674e157b6eed')
self.assertEqual(track.mbid, data['id'])
self.assertTrue(track.artist.pk is not None)
self.assertEqual(str(track.artist.mbid), '62c3befb-6366-4585-b256-809472333801')
self.assertEqual(track.artist.name, 'Adhesive Wombat')
self.assertEqual(str(track.album.mbid), 'a50d2a81-2a50-484d-9cb4-b9f6833f583e')
self.assertEqual(track.album.title, 'Marsupial Madness')
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['adhesive_wombat'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.get', return_value=api_data.albums['get']['marsupial'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.get', return_value=api_data.tracks['get']['8bitadventures'])
def test_can_create_track_from_api_with_corresponding_tags(self, *mocks):
track = models.Track.create_from_api(id='9968a9d6-8d92-4051-8f76-674e157b6eed')
expected_tags = ['techno', 'good-music']
track_tags = [tag.slug for tag in track.tags.all()]
for tag in expected_tags:
self.assertIn(tag, track_tags)
@unittest.mock.patch('funkwhale_api.musicbrainz.api.artists.get', return_value=api_data.artists['get']['adhesive_wombat'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.releases.get', return_value=api_data.albums['get']['marsupial'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.search', return_value=api_data.tracks['search']['8bitadventures'])
def test_can_get_or_create_track_from_api(self, *mocks):
track = models.Track.create_from_api(query="8-bit adventure")
data = models.Track.api.search(query='8-bit adventure')['recording-list'][0]
self.assertEqual(int(data['ext:score']), 100)
self.assertEqual(data['id'], '9968a9d6-8d92-4051-8f76-674e157b6eed')
self.assertEqual(track.mbid, data['id'])
self.assertTrue(track.artist.pk is not None)
self.assertEqual(str(track.artist.mbid), '62c3befb-6366-4585-b256-809472333801')
self.assertEqual(track.artist.name, 'Adhesive Wombat')
track2, created = models.Track.get_or_create_from_api(mbid=data['id'])
self.assertFalse(created)
self.assertEqual(track, track2)
def test_album_tags_deduced_from_tracks_tags(self):
tag = factories.TagFactory()
album = factories.AlbumFactory()
tracks = factories.TrackFactory.create_batch(album=album, size=5)
for track in tracks:
track.tags.add(tag)
album = models.Album.objects.prefetch_related('tracks__tags').get(pk=album.pk)
with self.assertNumQueries(0):
self.assertIn(tag, album.tags)
def test_artist_tags_deduced_from_album_tags(self):
tag = factories.TagFactory()
artist = factories.ArtistFactory()
album = factories.AlbumFactory(artist=artist)
tracks = factories.TrackFactory.create_batch(album=album, size=5)
for track in tracks:
track.tags.add(tag)
artist = models.Artist.objects.prefetch_related('albums__tracks__tags').get(pk=artist.pk)
with self.assertNumQueries(0):
self.assertIn(tag, artist.tags)
@unittest.mock.patch('funkwhale_api.musicbrainz.api.images.get_front', return_value=binary_data)
def test_can_download_image_file_for_album(self, *mocks):
# client._api.get_image_front('55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album = factories.AlbumFactory(mbid='55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album.get_image()
album.save()
self.assertEqual(album.cover.file.read(), binary_data)

Wyświetl plik

@ -1,66 +0,0 @@
import json
import unittest
from test_plus.test import TestCase
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from funkwhale_api.music.tests import factories
from funkwhale_api.users.models import User
from . import data as api_data
class TestWorks(TestCase):
@unittest.mock.patch('funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
def test_can_import_work(self, *mocks):
recording = factories.TrackFactory(
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
work = models.Work.create_from_api(id=mbid)
self.assertEqual(work.title, 'Chop Suey!')
self.assertEqual(work.nature, 'song')
self.assertEqual(work.language, 'eng')
self.assertEqual(work.mbid, mbid)
# a imported work should also be linked to corresponding recordings
recording.refresh_from_db()
self.assertEqual(recording.work, work)
@unittest.mock.patch('funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['chop_suey'])
def test_can_get_work_from_recording(self, *mocks):
recording = factories.TrackFactory(
work=None,
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
self.assertEqual(recording.work, None)
work = recording.get_work()
self.assertEqual(work.title, 'Chop Suey!')
self.assertEqual(work.nature, 'song')
self.assertEqual(work.language, 'eng')
self.assertEqual(work.mbid, mbid)
recording.refresh_from_db()
self.assertEqual(recording.work, work)
@unittest.mock.patch('funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
def test_works_import_lyrics_if_any(self, *mocks):
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
work = models.Work.create_from_api(id=mbid)
lyrics = models.Lyrics.objects.latest('id')
self.assertEqual(lyrics.work, work)
self.assertEqual(
lyrics.url, 'http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!')

Wyświetl plik

@ -1,87 +0,0 @@
import json
import unittest
from test_plus.test import TestCase
from django.urls import reverse
from funkwhale_api.musicbrainz import api
from . import data as api_data
class TestAPI(TestCase):
@unittest.mock.patch(
'funkwhale_api.musicbrainz.api.recordings.search',
return_value=api_data.recordings['search']['brontide matador'])
def test_can_search_recording_in_musicbrainz_api(self, *mocks):
query = 'brontide matador'
url = reverse('api:v1:providers:musicbrainz:search-recordings')
expected = api_data.recordings['search']['brontide matador']
response = self.client.get(url, data={'query': query})
self.assertEqual(expected, json.loads(response.content.decode('utf-8')))
@unittest.mock.patch(
'funkwhale_api.musicbrainz.api.releases.search',
return_value=api_data.releases['search']['brontide matador'])
def test_can_search_release_in_musicbrainz_api(self, *mocks):
query = 'brontide matador'
url = reverse('api:v1:providers:musicbrainz:search-releases')
expected = api_data.releases['search']['brontide matador']
response = self.client.get(url, data={'query': query})
self.assertEqual(expected, json.loads(response.content.decode('utf-8')))
@unittest.mock.patch(
'funkwhale_api.musicbrainz.api.artists.search',
return_value=api_data.artists['search']['lost fingers'])
def test_can_search_artists_in_musicbrainz_api(self, *mocks):
query = 'lost fingers'
url = reverse('api:v1:providers:musicbrainz:search-artists')
expected = api_data.artists['search']['lost fingers']
response = self.client.get(url, data={'query': query})
self.assertEqual(expected, json.loads(response.content.decode('utf-8')))
@unittest.mock.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['lost fingers'])
def test_can_get_artist_in_musicbrainz_api(self, *mocks):
uuid = 'ac16bbc0-aded-4477-a3c3-1d81693d58c9'
url = reverse('api:v1:providers:musicbrainz:artist-detail', kwargs={
'uuid': uuid,
})
response = self.client.get(url)
expected = api_data.artists['get']['lost fingers']
self.assertEqual(expected, json.loads(response.content.decode('utf-8')))
@unittest.mock.patch(
'funkwhale_api.musicbrainz.api.release_groups.browse',
return_value=api_data.release_groups['browse']['lost fingers'])
def test_can_broswe_release_group_using_musicbrainz_api(self, *mocks):
uuid = 'ac16bbc0-aded-4477-a3c3-1d81693d58c9'
url = reverse(
'api:v1:providers:musicbrainz:release-group-browse',
kwargs={
'artist_uuid': uuid,
}
)
response = self.client.get(url)
expected = api_data.release_groups['browse']['lost fingers']
self.assertEqual(expected, json.loads(response.content.decode('utf-8')))
@unittest.mock.patch(
'funkwhale_api.musicbrainz.api.releases.browse',
return_value=api_data.releases['browse']['Lost in the 80s'])
def test_can_broswe_releases_using_musicbrainz_api(self, *mocks):
uuid = 'f04ed607-11b7-3843-957e-503ecdd485d1'
url = reverse(
'api:v1:providers:musicbrainz:release-browse',
kwargs={
'release_group_uuid': uuid,
}
)
response = self.client.get(url)
expected = api_data.releases['browse']['Lost in the 80s']
self.assertEqual(expected, json.loads(response.content.decode('utf-8')))

Wyświetl plik

@ -1,17 +0,0 @@
import unittest
from test_plus.test import TestCase
from funkwhale_api.musicbrainz import client
class TestAPI(TestCase):
def test_can_search_recording_in_musicbrainz_api(self, *mocks):
r = {'hello': 'world'}
mocked = 'funkwhale_api.musicbrainz.client._api.search_artists'
with unittest.mock.patch(mocked, return_value=r) as m:
self.assertEqual(client.api.artists.search('test'), r)
# now call from cache
self.assertEqual(client.api.artists.search('test'), r)
self.assertEqual(client.api.artists.search('test'), r)
self.assertEqual(m.call_count, 1)

Wyświetl plik

@ -0,0 +1,13 @@
import factory
from funkwhale_api.factories import registry
from funkwhale_api.users.factories import UserFactory
@registry.register
class PlaylistFactory(factory.django.DjangoModelFactory):
name = factory.Faker('name')
user = factory.SubFactory(UserFactory)
class Meta:
model = 'playlists.Playlist'

Wyświetl plik

@ -1,64 +0,0 @@
import json
from test_plus.test import TestCase
from django.urls import reverse
from django.core.exceptions import ValidationError
from django.utils import timezone
from funkwhale_api.music.tests import factories
from funkwhale_api.users.models import User
from funkwhale_api.playlists import models
from funkwhale_api.playlists.serializers import PlaylistSerializer
class TestPlayLists(TestCase):
def setUp(self):
super().setUp()
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_can_create_playlist(self):
tracks = factories.TrackFactory.create_batch(size=5)
playlist = models.Playlist.objects.create(user=self.user, name="test")
previous = None
for i in range(len(tracks)):
previous = playlist.add_track(tracks[i], previous=previous)
playlist_tracks = list(playlist.playlist_tracks.all())
previous = None
for idx, track in enumerate(tracks):
plt = playlist_tracks[idx]
self.assertEqual(plt.position, idx)
self.assertEqual(plt.track, track)
if previous:
self.assertEqual(playlist_tracks[idx + 1], previous)
self.assertEqual(plt.playlist, playlist)
def test_can_create_playlist_via_api(self):
self.client.login(username=self.user.username, password='test')
url = reverse('api:v1:playlists-list')
data = {
'name': 'test',
}
response = self.client.post(url, data)
playlist = self.user.playlists.latest('id')
self.assertEqual(playlist.name, 'test')
def test_can_add_playlist_track_via_api(self):
tracks = factories.TrackFactory.create_batch(size=5)
playlist = models.Playlist.objects.create(user=self.user, name="test")
self.client.login(username=self.user.username, password='test')
url = reverse('api:v1:playlist-tracks-list')
data = {
'playlist': playlist.pk,
'track': tracks[0].pk
}
response = self.client.post(url, data)
plts = self.user.playlists.latest('id').playlist_tracks.all()
self.assertEqual(plts.first().track, tracks[0])

Wyświetl plik

@ -1,50 +0,0 @@
import os
import datetime
import unittest
from test_plus.test import TestCase
from funkwhale_api.providers.audiofile import tasks
DATA_DIR = os.path.dirname(os.path.abspath(__file__))
class TestAudioFile(TestCase):
def test_can_import_single_audio_file(self, *mocks):
metadata = {
'artist': ['Test artist'],
'album': ['Test album'],
'title': ['Test track'],
'TRACKNUMBER': ['4'],
'date': ['2012-08-15'],
'musicbrainz_albumid': ['a766da8b-8336-47aa-a3ee-371cc41ccc75'],
'musicbrainz_trackid': ['bd21ac48-46d8-4e78-925f-d9cc2a294656'],
'musicbrainz_artistid': ['013c8e5b-d72a-4cd3-8dee-6c64d6125823'],
}
m1 = unittest.mock.patch('mutagen.File', return_value=metadata)
m2 = unittest.mock.patch(
'funkwhale_api.music.metadata.Metadata.get_file_type',
return_value='OggVorbis',
)
with m1, m2:
track_file = tasks.from_path(
os.path.join(DATA_DIR, 'dummy_file.ogg'))
self.assertEqual(
track_file.track.title, metadata['title'][0])
self.assertEqual(
track_file.track.mbid, metadata['musicbrainz_trackid'][0])
self.assertEqual(
track_file.track.position, 4)
self.assertEqual(
track_file.track.album.title, metadata['album'][0])
self.assertEqual(
track_file.track.album.mbid,
metadata['musicbrainz_albumid'][0])
self.assertEqual(
track_file.track.album.release_date, datetime.date(2012, 8, 15))
self.assertEqual(
track_file.track.artist.name, metadata['artist'][0])
self.assertEqual(
track_file.track.artist.mbid,
metadata['musicbrainz_artistid'][0])

Wyświetl plik

@ -1,99 +0,0 @@
import json
from collections import OrderedDict
import unittest
from test_plus.test import TestCase
from django.urls import reverse
from funkwhale_api.providers.youtube.client import client
from . import data as api_data
class TestAPI(TestCase):
maxDiff = None
@unittest.mock.patch(
'funkwhale_api.providers.youtube.client._do_search',
return_value=api_data.search['8 bit adventure'])
def test_can_get_search_results_from_youtube(self, *mocks):
query = '8 bit adventure'
results = client.search(query)
self.assertEqual(results[0]['id']['videoId'], '0HxZn6CzOIo')
self.assertEqual(results[0]['snippet']['title'], 'AdhesiveWombat - 8 Bit Adventure')
self.assertEqual(results[0]['full_url'], 'https://www.youtube.com/watch?v=0HxZn6CzOIo')
@unittest.mock.patch(
'funkwhale_api.providers.youtube.client._do_search',
return_value=api_data.search['8 bit adventure'])
def test_can_get_search_results_from_funkwhale(self, *mocks):
query = '8 bit adventure'
url = self.reverse('api:v1:providers:youtube:search')
response = self.client.get(url + '?query={0}'.format(query))
# we should cast the youtube result to something more generic
expected = {
"id": "0HxZn6CzOIo",
"url": "https://www.youtube.com/watch?v=0HxZn6CzOIo",
"type": "youtube#video",
"description": "Make sure to apply adhesive evenly before use. GET IT HERE: http://adhesivewombat.bandcamp.com/album/marsupial-madness Facebook: ...",
"channelId": "UCps63j3krzAG4OyXeEyuhFw",
"title": "AdhesiveWombat - 8 Bit Adventure",
"channelTitle": "AdhesiveWombat",
"publishedAt": "2012-08-22T18:41:03.000Z",
"cover": "https://i.ytimg.com/vi/0HxZn6CzOIo/hqdefault.jpg"
}
self.assertEqual(
json.loads(response.content.decode('utf-8'))[0], expected)
@unittest.mock.patch(
'funkwhale_api.providers.youtube.client._do_search',
side_effect=[
api_data.search['8 bit adventure'],
api_data.search['system of a down toxicity'],
]
)
def test_can_send_multiple_queries_at_once(self, *mocks):
queries = OrderedDict()
queries['1'] = {
'q': '8 bit adventure',
}
queries['2'] = {
'q': 'system of a down toxicity',
}
results = client.search_multiple(queries)
self.assertEqual(results['1'][0]['id']['videoId'], '0HxZn6CzOIo')
self.assertEqual(results['1'][0]['snippet']['title'], 'AdhesiveWombat - 8 Bit Adventure')
self.assertEqual(results['1'][0]['full_url'], 'https://www.youtube.com/watch?v=0HxZn6CzOIo')
self.assertEqual(results['2'][0]['id']['videoId'], 'BorYwGi2SJc')
self.assertEqual(results['2'][0]['snippet']['title'], 'System of a Down: Toxicity')
self.assertEqual(results['2'][0]['full_url'], 'https://www.youtube.com/watch?v=BorYwGi2SJc')
@unittest.mock.patch(
'funkwhale_api.providers.youtube.client._do_search',
return_value=api_data.search['8 bit adventure'],
)
def test_can_send_multiple_queries_at_once_from_funwkhale(self, *mocks):
queries = OrderedDict()
queries['1'] = {
'q': '8 bit adventure',
}
expected = {
"id": "0HxZn6CzOIo",
"url": "https://www.youtube.com/watch?v=0HxZn6CzOIo",
"type": "youtube#video",
"description": "Make sure to apply adhesive evenly before use. GET IT HERE: http://adhesivewombat.bandcamp.com/album/marsupial-madness Facebook: ...",
"channelId": "UCps63j3krzAG4OyXeEyuhFw",
"title": "AdhesiveWombat - 8 Bit Adventure",
"channelTitle": "AdhesiveWombat",
"publishedAt": "2012-08-22T18:41:03.000Z",
"cover": "https://i.ytimg.com/vi/0HxZn6CzOIo/hqdefault.jpg"
}
url = self.reverse('api:v1:providers:youtube:searchs')
response = self.client.post(
url, json.dumps(queries), content_type='application/json')
self.assertEqual(
expected,
json.loads(response.content.decode('utf-8'))['1'][0])

Wyświetl plik

@ -1,196 +0,0 @@
import random
import json
from test_plus.test import TestCase
from django.urls import reverse
from django.core.exceptions import ValidationError
from funkwhale_api.radios import radios
from funkwhale_api.radios import models
from funkwhale_api.favorites.models import TrackFavorite
from funkwhale_api.users.models import User
from funkwhale_api.music.models import Artist
from funkwhale_api.music.tests import factories
from funkwhale_api.history.tests.factories import ListeningFactory
class TestRadios(TestCase):
def setUp(self):
super().setUp()
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_can_pick_track_from_choices(self):
choices = [1, 2, 3, 4, 5]
radio = radios.SimpleRadio()
first_pick = radio.pick(choices=choices)
self.assertIn(first_pick, choices)
previous_choices = [first_pick]
for remaining_choice in choices:
pick = radio.pick(choices=choices, previous_choices=previous_choices)
self.assertIn(pick, set(choices).difference(previous_choices))
def test_can_pick_by_weight(self):
choices_with_weight = [
# choice, weight
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
]
picks = {choice: 0 for choice, weight in choices_with_weight}
for i in range(1000):
radio = radios.SimpleRadio()
pick = radio.weighted_pick(choices=choices_with_weight)
picks[pick] = picks[pick] + 1
self.assertTrue(picks[5] > picks[4])
self.assertTrue(picks[4] > picks[3])
self.assertTrue(picks[3] > picks[2])
self.assertTrue(picks[2] > picks[1])
def test_can_get_choices_for_favorites_radio(self):
tracks = factories.TrackFactory.create_batch(size=100)
for i in range(20):
TrackFavorite.add(track=random.choice(tracks), user=self.user)
radio = radios.FavoritesRadio()
choices = radio.get_choices(user=self.user)
self.assertEqual(choices.count(), self.user.track_favorites.all().count())
for favorite in self.user.track_favorites.all():
self.assertIn(favorite.track, choices)
for i in range(20):
pick = radio.pick(user=self.user)
self.assertIn(pick, choices)
def test_can_use_radio_session_to_filter_choices(self):
tracks = factories.TrackFactory.create_batch(size=30)
radio = radios.RandomRadio()
session = radio.start_session(self.user)
for i in range(30):
p = radio.pick()
# ensure 30 differents tracks have been suggested
tracks_id = [session_track.track.pk for session_track in session.session_tracks.all()]
self.assertEqual(len(set(tracks_id)), 30)
def test_can_restore_radio_from_previous_session(self):
tracks = factories.TrackFactory.create_batch(size=30)
radio = radios.RandomRadio()
session = radio.start_session(self.user)
restarted_radio = radios.RandomRadio(session)
self.assertEqual(radio.session, restarted_radio.session)
def test_can_get_start_radio_from_api(self):
url = reverse('api:v1:radios:sessions-list')
response = self.client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
self.assertEqual(session.radio_type, 'random')
self.assertEqual(session.user, None)
self.client.login(username=self.user.username, password='test')
response = self.client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
self.assertEqual(session.radio_type, 'random')
self.assertEqual(session.user, self.user)
def test_can_start_radio_for_anonymous_user(self):
url = reverse('api:v1:radios:sessions-list')
response = self.client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
self.assertIsNone(session.user)
self.assertIsNotNone(session.session_key)
def test_can_get_track_for_session_from_api(self):
tracks = factories.TrackFactory.create_batch(size=1)
self.client.login(username=self.user.username, password='test')
url = reverse('api:v1:radios:sessions-list')
response = self.client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
url = reverse('api:v1:radios:tracks-list')
response = self.client.post(url, {'session': session.pk})
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data['track']['id'], tracks[0].id)
self.assertEqual(data['position'], 1)
next_track = factories.TrackFactory()
response = self.client.post(url, {'session': session.pk})
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data['track']['id'], next_track.id)
self.assertEqual(data['position'], 2)
def test_related_object_radio_validate_related_object(self):
# cannot start without related object
radio = radios.ArtistRadio()
with self.assertRaises(ValidationError):
radio.start_session(self.user)
# cannot start with bad related object type
radio = radios.ArtistRadio()
with self.assertRaises(ValidationError):
radio.start_session(self.user, related_object=self.user)
def test_can_start_artist_radio(self):
artist = factories.ArtistFactory()
wrong_tracks = factories.TrackFactory.create_batch(size=30)
good_tracks = factories.TrackFactory.create_batch(
artist=artist, size=5)
radio = radios.ArtistRadio()
session = radio.start_session(self.user, related_object=artist)
self.assertEqual(session.radio_type, 'artist')
for i in range(5):
self.assertIn(radio.pick(), good_tracks)
def test_can_start_tag_radio(self):
tag = factories.TagFactory()
wrong_tracks = factories.TrackFactory.create_batch(size=30)
good_tracks = factories.TrackFactory.create_batch(size=5)
for track in good_tracks:
track.tags.add(tag)
radio = radios.TagRadio()
session = radio.start_session(self.user, related_object=tag)
self.assertEqual(session.radio_type, 'tag')
for i in range(5):
self.assertIn(radio.pick(), good_tracks)
def test_can_start_artist_radio_from_api(self):
artist = factories.ArtistFactory()
url = reverse('api:v1:radios:sessions-list')
response = self.client.post(url, {'radio_type': 'artist', 'related_object_id': artist.id})
session = models.RadioSession.objects.latest('id')
self.assertEqual(session.radio_type, 'artist')
self.assertEqual(session.related_object, artist)
def test_can_start_less_listened_radio(self):
history = ListeningFactory.create_batch(size=5, user=self.user)
wrong_tracks = [h.track for h in history]
good_tracks = factories.TrackFactory.create_batch(size=30)
radio = radios.LessListenedRadio()
session = radio.start_session(self.user)
self.assertEqual(session.related_object, self.user)
for i in range(5):
self.assertIn(radio.pick(), good_tracks)

Wyświetl plik

@ -1,12 +1,14 @@
import factory
from funkwhale_api.factories import registry
from django.contrib.auth.models import Permission
@registry.register
class UserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: 'user-{0}'.format(n))
email = factory.Sequence(lambda n: 'user-{0}@example.com'.format(n))
password = factory.PostGenerationMethodCall('set_password', 'password')
password = factory.PostGenerationMethodCall('set_password', 'test')
class Meta:
model = 'users.User'
@ -28,3 +30,9 @@ class UserFactory(factory.django.DjangoModelFactory):
]
# A list of permissions were passed in, use them
self.user_permissions.add(*perms)
@registry.register(name='users.SuperUser')
class SuperUserFactory(UserFactory):
is_staff = True
is_superuser = True

Wyświetl plik

@ -1,40 +0,0 @@
from test_plus.test import TestCase
from ..admin import MyUserCreationForm
class TestMyUserCreationForm(TestCase):
def setUp(self):
self.user = self.make_user()
def test_clean_username_success(self):
# Instantiate the form with a new username
form = MyUserCreationForm({
'username': 'alamode',
'password1': '123456',
'password2': '123456',
})
# Run is_valid() to trigger the validation
valid = form.is_valid()
self.assertTrue(valid)
# Run the actual clean_username method
username = form.clean_username()
self.assertEqual('alamode', username)
def test_clean_username_false(self):
# Instantiate the form with the same username as self.user
form = MyUserCreationForm({
'username': self.user.username,
'password1': '123456',
'password2': '123456',
})
# Run is_valid() to trigger the validation, which is going to fail
# because the username is already taken
valid = form.is_valid()
self.assertFalse(valid)
# The form.errors dict should contain a single error called 'username'
self.assertTrue(len(form.errors) == 1)
self.assertTrue('username' in form.errors)

Wyświetl plik

@ -1,13 +0,0 @@
from test_plus.test import TestCase
class TestUser(TestCase):
def setUp(self):
self.user = self.make_user()
def test__str__(self):
self.assertEqual(
self.user.__str__(),
"testuser" # This is the default username for self.make_user()
)

Wyświetl plik

@ -1,73 +0,0 @@
import json
from django.test import RequestFactory
from test_plus.test import TestCase
from funkwhale_api.users.models import User
from . factories import UserFactory
class UserTestCase(TestCase):
def setUp(self):
self.user = self.make_user()
self.factory = RequestFactory()
def test_can_create_user_via_api(self):
url = self.reverse('rest_register')
data = {
'username': 'test1',
'email': 'test1@test.com',
'password1': 'testtest',
'password2': 'testtest',
}
with self.settings(REGISTRATION_MODE="public"):
response = self.client.post(url, data)
self.assertEqual(response.status_code, 201)
u = User.objects.get(email='test1@test.com')
self.assertEqual(u.username, 'test1')
def test_can_disable_registration_view(self):
url = self.reverse('rest_register')
data = {
'username': 'test1',
'email': 'test1@test.com',
'password1': 'testtest',
'password2': 'testtest',
}
with self.settings(REGISTRATION_MODE="disabled"):
response = self.client.post(url, data)
self.assertEqual(response.status_code, 403)
def test_can_fetch_data_from_api(self):
url = self.reverse('api:v1:users:users-me')
response = self.client.get(url)
# login required
self.assertEqual(response.status_code, 401)
user = UserFactory(
is_staff=True,
perms=[
'music.add_importbatch',
'dynamic_preferences.change_globalpreferencemodel',
]
)
self.assertTrue(user.has_perm('music.add_importbatch'))
self.login(user)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
payload = json.loads(response.content.decode('utf-8'))
self.assertEqual(payload['username'], user.username)
self.assertEqual(payload['is_staff'], user.is_staff)
self.assertEqual(payload['is_superuser'], user.is_superuser)
self.assertEqual(payload['email'], user.email)
self.assertEqual(payload['name'], user.name)
self.assertEqual(
payload['permissions']['import.launch']['status'], True)
self.assertEqual(
payload['permissions']['settings.change']['status'], True)

Wyświetl plik

@ -1,12 +0,0 @@
import tempfile
import shutil
class TMPDirTestCaseMixin(object):
def setUp(self):
super().tearDown()
self.download_dir = tempfile.mkdtemp()
def tearDown(self):
super().tearDown()
shutil.rmtree(self.download_dir)

Wyświetl plik

@ -5,7 +5,6 @@ django_coverage_plugin>=1.5,<1.6
Sphinx>=1.6,<1.7
django-extensions>=1.9,<1.10
Werkzeug>=0.13,<0.14
django-test-plus>=1.0.20
factory_boy>=2.8.1
# django-debug-toolbar that works with Django 1.5+

Wyświetl plik

@ -2,7 +2,10 @@
flake8
pytest
pytest-django
# pytest-django until a new release containing django_assert_num_queries
# is deployed to pypi
git+https://github.com/pytest-dev/pytest-django.git@d3d9bb3ef6f0377cb5356eb368992a0834692378
pytest-mock
pytest-sugar
pytest-xdist

Wyświetl plik

@ -0,0 +1,42 @@
import tempfile
import shutil
import pytest
@pytest.fixture(scope="session", autouse=True)
def factories_autodiscover():
from django.apps import apps
from funkwhale_api import factories
app_names = [app.name for app in apps.app_configs.values()]
factories.registry.autodiscover(app_names)
@pytest.fixture
def factories(db):
from funkwhale_api import factories
yield factories.registry
@pytest.fixture
def tmpdir():
d = tempfile.mkdtemp()
yield d
shutil.rmtree(d)
@pytest.fixture
def logged_in_client(db, factories, client):
user = factories['users.User']()
assert client.login(username=user.username, password='test')
setattr(client, 'user', user)
yield client
delattr(client, 'user')
@pytest.fixture
def superuser_client(db, factories, client):
user = factories['users.SuperUser']()
assert client.login(username=user.username, password='test')
setattr(client, 'user', user)
yield client
delattr(client, 'user')

Wyświetl plik

@ -0,0 +1,253 @@
import json
import pytest
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from . import data as api_data
def test_can_submit_youtube_url_for_track_import(mocker, superuser_client):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['adhesive_wombat'])
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.get',
return_value=api_data.albums['get']['marsupial'])
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['8bitadventures'])
mocker.patch(
'funkwhale_api.music.models.TrackFile.download_file',
return_value=None)
mbid = '9968a9d6-8d92-4051-8f76-674e157b6eed'
video_id = 'tPEE9ZwTmy0'
url = reverse('api:v1:submit-single')
response = superuser_client.post(
url,
{'import_url': 'https://www.youtube.com/watch?v={0}'.format(video_id),
'mbid': mbid})
track = models.Track.objects.get(mbid=mbid)
assert track.artist.name == 'Adhesive Wombat'
assert track.album.title == 'Marsupial Madness'
def test_import_creates_an_import_with_correct_data(superuser_client, settings):
mbid = '9968a9d6-8d92-4051-8f76-674e157b6eed'
video_id = 'tPEE9ZwTmy0'
url = reverse('api:v1:submit-single')
settings.CELERY_ALWAYS_EAGER = False
response = superuser_client.post(
url,
{'import_url': 'https://www.youtube.com/watch?v={0}'.format(video_id),
'mbid': mbid})
batch = models.ImportBatch.objects.latest('id')
assert batch.jobs.count() == 1
assert batch.submitted_by == superuser_client.user
assert batch.status == 'pending'
job = batch.jobs.first()
assert str(job.mbid) == mbid
assert job.status == 'pending'
assert job.source == 'https://www.youtube.com/watch?v={0}'.format(video_id)
def test_can_import_whole_album(mocker, superuser_client, settings):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.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=api_data.albums['get_with_includes']['hypnotize'])
payload = {
'releaseId': '47ae093f-1607-49a3-be11-a15d335ccc94',
'tracks': [
{
'mbid': '1968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=1111111111',
},
{
'mbid': '2968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=2222222222',
},
{
'mbid': '3968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=3333333333',
},
]
}
url = reverse('api:v1:submit-album')
settings.CELERY_ALWAYS_EAGER = False
response = superuser_client.post(
url, json.dumps(payload), content_type="application/json")
batch = models.ImportBatch.objects.latest('id')
assert batch.jobs.count() == 3
assert batch.submitted_by == superuser_client.user
assert batch.status == 'pending'
album = models.Album.objects.latest('id')
assert str(album.mbid) == '47ae093f-1607-49a3-be11-a15d335ccc94'
medium_data = api_data.albums['get_with_includes']['hypnotize']['release']['medium-list'][0]
assert int(medium_data['track-count']) == album.tracks.all().count()
for track in medium_data['track-list']:
instance = models.Track.objects.get(mbid=track['recording']['id'])
assert instance.title == track['recording']['title']
assert instance.position == int(track['position'])
assert instance.title == track['recording']['title']
for row in payload['tracks']:
job = models.ImportJob.objects.get(mbid=row['mbid'])
assert str(job.mbid) == row['mbid']
assert job.status == 'pending'
assert job.source == row['source']
def test_can_import_whole_artist(mocker, superuser_client, settings):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.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=api_data.albums['get_with_includes']['hypnotize'])
payload = {
'artistId': 'mbid',
'albums': [
{
'releaseId': '47ae093f-1607-49a3-be11-a15d335ccc94',
'tracks': [
{
'mbid': '1968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=1111111111',
},
{
'mbid': '2968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=2222222222',
},
{
'mbid': '3968a9d6-8d92-4051-8f76-674e157b6eed',
'source': 'https://www.youtube.com/watch?v=3333333333',
},
]
}
]
}
url = reverse('api:v1:submit-artist')
settings.CELERY_ALWAYS_EAGER = False
response = superuser_client.post(
url, json.dumps(payload), content_type="application/json")
batch = models.ImportBatch.objects.latest('id')
assert batch.jobs.count() == 3
assert batch.submitted_by == superuser_client.user
assert batch.status == 'pending'
album = models.Album.objects.latest('id')
assert str(album.mbid) == '47ae093f-1607-49a3-be11-a15d335ccc94'
medium_data = api_data.albums['get_with_includes']['hypnotize']['release']['medium-list'][0]
assert int(medium_data['track-count']) == album.tracks.all().count()
for track in medium_data['track-list']:
instance = models.Track.objects.get(mbid=track['recording']['id'])
assert instance.title == track['recording']['title']
assert instance.position == int(track['position'])
assert instance.title == track['recording']['title']
for row in payload['albums'][0]['tracks']:
job = models.ImportJob.objects.get(mbid=row['mbid'])
assert str(job.mbid) == row['mbid']
assert job.status == 'pending'
assert job.source == row['source']
def test_user_can_query_api_for_his_own_batches(client, factories):
user1 = factories['users.SuperUser']()
user2 = factories['users.SuperUser']()
job = factories['music.ImportJob'](batch__submitted_by=user1)
url = reverse('api:v1:import-batches-list')
client.login(username=user2.username, password='test')
response2 = client.get(url)
results = json.loads(response2.content.decode('utf-8'))
assert results['count'] == 0
client.logout()
client.login(username=user1.username, password='test')
response1 = client.get(url)
results = json.loads(response1.content.decode('utf-8'))
assert results['count'] == 1
assert results['results'][0]['jobs'][0]['mbid'] == job.mbid
def test_can_search_artist(factories, client):
artist1 = factories['music.Artist']()
artist2 = factories['music.Artist']()
expected = [serializers.ArtistSerializerNested(artist1).data]
url = reverse('api:v1:artists-search')
response = client.get(url, {'query': artist1.name})
assert json.loads(response.content.decode('utf-8')) == expected
def test_can_search_artist_by_name_start(factories, client):
artist1 = factories['music.Artist'](name='alpha')
artist2 = factories['music.Artist'](name='beta')
expected = {
'next': None,
'previous': None,
'count': 1,
'results': [serializers.ArtistSerializerNested(artist1).data]
}
url = reverse('api:v1:artists-list')
response = client.get(url, {'name__startswith': 'a'})
assert expected == json.loads(response.content.decode('utf-8'))
def test_can_search_tracks(factories, client):
track1 = factories['music.Track'](title="test track 1")
track2 = factories['music.Track']()
query = 'test track 1'
expected = [serializers.TrackSerializerNested(track1).data]
url = reverse('api:v1:tracks-search')
response = client.get(url, {'query': query})
assert expected == json.loads(response.content.decode('utf-8'))
@pytest.mark.parametrize('route,method', [
('api:v1:tags-list', 'get'),
('api:v1:tracks-list', 'get'),
('api:v1:artists-list', 'get'),
('api:v1:albums-list', 'get'),
])
def test_can_restrict_api_views_to_authenticated_users(db, route, method, settings, client):
url = reverse(route)
settings.API_AUTHENTICATION_REQUIRED = True
response = getattr(client, method)(url)
assert response.status_code == 401
def test_track_file_url_is_restricted_to_authenticated_users(client, factories, settings):
settings.API_AUTHENTICATION_REQUIRED = True
f = factories['music.TrackFile']()
assert f.audio_file is not None
url = f.path
response = client.get(url)
assert response.status_code == 401
user = factories['users.SuperUser']()
client.login(username=user.username, password='test')
response = client.get(url)
assert response.status_code == 200
assert response['X-Accel-Redirect'] == '/_protected{}'.format(f.audio_file.url)

Wyświetl plik

@ -0,0 +1,73 @@
import json
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from funkwhale_api.music import lyrics as lyrics_utils
from .mocking import lyricswiki
from . import data as api_data
def test_works_import_lyrics_if_any(mocker, factories):
mocker.patch(
'funkwhale_api.music.lyrics._get_html',
return_value=lyricswiki.content)
lyrics = factories['music.Lyrics'](
url='http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!')
lyrics.fetch_content()
self.assertIn(
'Grab a brush and put on a little makeup',
lyrics.content,
)
def test_clean_content():
c = """<div class="lyricbox">Hello<br /><script>alert('hello');</script>Is it me you're looking for?<br /></div>"""
d = lyrics_utils.extract_content(c)
d = lyrics_utils.clean_content(d)
expected = """Hello
Is it me you're looking for?
"""
assert d == expected
def test_markdown_rendering(factories):
content = """Hello
Is it me you're looking for?"""
l = factories['music.Lyrics'](content=content)
expected = "<p>Hello<br />\nIs it me you're looking for?</p>"
assert expected == l.content_rendered
def test_works_import_lyrics_if_any(mocker, factories, logged_in_client):
mocker.patch(
'funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['chop_suey'])
mocker.patch(
'funkwhale_api.music.lyrics._get_html',
return_value=lyricswiki.content)
track = factories['music.Track'](
work=None,
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
url = reverse('api:v1:tracks-lyrics', kwargs={'pk': track.pk})
response = logged_in_client.get(url)
assert response.status_code == 200
track.refresh_from_db()
lyrics = models.Lyrics.objects.latest('id')
work = models.Work.objects.latest('id')
assert track.work == work
assert lyrics.work == work

Wyświetl plik

@ -0,0 +1,41 @@
import datetime
import os
import pytest
from funkwhale_api.music import metadata
DATA_DIR = os.path.dirname(os.path.abspath(__file__))
@pytest.mark.parametrize('field,value', [
('title', 'Peer Gynt Suite no. 1, op. 46: I. Morning'),
('artist', 'Edvard Grieg'),
('album', 'Peer Gynt Suite no. 1, op. 46'),
('date', datetime.date(2012, 8, 15)),
('track_number', 1),
('musicbrainz_albumid', 'a766da8b-8336-47aa-a3ee-371cc41ccc75'),
('musicbrainz_recordingid', 'bd21ac48-46d8-4e78-925f-d9cc2a294656'),
('musicbrainz_artistid', '013c8e5b-d72a-4cd3-8dee-6c64d6125823'),
])
def test_can_get_metadata_from_ogg_file(field, value):
path = os.path.join(DATA_DIR, 'test.ogg')
data = metadata.Metadata(path)
assert data.get(field) == value
@pytest.mark.parametrize('field,value', [
('title', 'Bend'),
('artist', 'Binärpilot'),
('album', 'You Can\'t Stop Da Funk'),
('date', datetime.date(2006, 2, 7)),
('track_number', 1),
('musicbrainz_albumid', 'ce40cdb1-a562-4fd8-a269-9269f98d4124'),
('musicbrainz_recordingid', 'f269d497-1cc0-4ae4-a0c4-157ec7d73fcb'),
('musicbrainz_artistid', '9c6bddde-6228-4d9f-ad0d-03f6fcb19e13'),
])
def test_can_get_metadata_from_id3_mp3_file(field, value):
path = os.path.join(DATA_DIR, 'test.mp3')
data = metadata.Metadata(path)
assert data.get(field) == value

Wyświetl plik

@ -2,16 +2,14 @@ import pytest
from funkwhale_api.music import models
from funkwhale_api.music import importers
from . import factories
def test_can_store_release_group_id_on_album(db):
album = factories.AlbumFactory()
def test_can_store_release_group_id_on_album(factories):
album = factories['music.Album']()
assert album.release_group_id is not None
def test_import_album_stores_release_group(db):
def test_import_album_stores_release_group(factories):
album_data = {
"artist-credit": [
{
@ -31,7 +29,7 @@ def test_import_album_stores_release_group(db):
"title": "Marsupial Madness",
'release-group': {'id': '447b4979-2178-405c-bfe6-46bf0b09e6c7'}
}
artist = factories.ArtistFactory(
artist = factories['music.Artist'](
mbid=album_data['artist-credit'][0]['artist']['id']
)
cleaned_data = models.Album.clean_musicbrainz_data(album_data)
@ -41,9 +39,9 @@ def test_import_album_stores_release_group(db):
assert album.artist == artist
def test_import_job_is_bound_to_track_file(db, mocker):
track = factories.TrackFactory()
job = factories.ImportJobFactory(mbid=track.mbid)
def test_import_job_is_bound_to_track_file(factories, mocker):
track = factories['music.Track']()
job = factories['music.ImportJob'](mbid=track.mbid)
mocker.patch('funkwhale_api.music.models.TrackFile.download_file')
job.run()

Wyświetl plik

@ -0,0 +1,138 @@
import pytest
from funkwhale_api.music import models
import datetime
from . import data as api_data
from .cover import binary_data
def test_can_create_artist_from_api(mocker, db):
mocker.patch(
'musicbrainzngs.search_artists',
return_value=api_data.artists['search']['adhesive_wombat'])
artist = models.Artist.create_from_api(query="Adhesive wombat")
data = models.Artist.api.search(query='Adhesive wombat')['artist-list'][0]
assert int(data['ext:score']), 100
assert data['id'], '62c3befb-6366-4585-b256-809472333801'
assert artist.mbid, data['id']
assert artist.name, 'Adhesive Wombat'
def test_can_create_album_from_api(mocker, db):
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.search',
return_value=api_data.albums['search']['hypnotize'])
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['soad'])
album = models.Album.create_from_api(query="Hypnotize", artist='system of a down', type='album')
data = models.Album.api.search(query='Hypnotize', artist='system of a down', type='album')['release-list'][0]
assert album.mbid, data['id']
assert album.title, 'Hypnotize'
with pytest.raises(ValueError):
assert album.cover.path is not None
assert album.release_date, datetime.date(2005, 1, 1)
assert album.artist.name, 'System of a Down'
assert album.artist.mbid, data['artist-credit'][0]['artist']['id']
def test_can_create_track_from_api(mocker, db):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['adhesive_wombat'])
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.get',
return_value=api_data.albums['get']['marsupial'])
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.search',
return_value=api_data.tracks['search']['8bitadventures'])
track = models.Track.create_from_api(query="8-bit adventure")
data = models.Track.api.search(query='8-bit adventure')['recording-list'][0]
assert int(data['ext:score']) == 100
assert data['id'] == '9968a9d6-8d92-4051-8f76-674e157b6eed'
assert track.mbid == data['id']
assert track.artist.pk is not None
assert str(track.artist.mbid) == '62c3befb-6366-4585-b256-809472333801'
assert track.artist.name == 'Adhesive Wombat'
assert str(track.album.mbid) == 'a50d2a81-2a50-484d-9cb4-b9f6833f583e'
assert track.album.title == 'Marsupial Madness'
def test_can_create_track_from_api_with_corresponding_tags(mocker, db):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['adhesive_wombat'])
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.get',
return_value=api_data.albums['get']['marsupial'])
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['8bitadventures'])
track = models.Track.create_from_api(id='9968a9d6-8d92-4051-8f76-674e157b6eed')
expected_tags = ['techno', 'good-music']
track_tags = [tag.slug for tag in track.tags.all()]
for tag in expected_tags:
assert tag in track_tags
def test_can_get_or_create_track_from_api(mocker, db):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['adhesive_wombat'])
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.get',
return_value=api_data.albums['get']['marsupial'])
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.search',
return_value=api_data.tracks['search']['8bitadventures'])
track = models.Track.create_from_api(query="8-bit adventure")
data = models.Track.api.search(query='8-bit adventure')['recording-list'][0]
assert int(data['ext:score']) == 100
assert data['id'] == '9968a9d6-8d92-4051-8f76-674e157b6eed'
assert track.mbid == data['id']
assert track.artist.pk is not None
assert str(track.artist.mbid) == '62c3befb-6366-4585-b256-809472333801'
assert track.artist.name == 'Adhesive Wombat'
track2, created = models.Track.get_or_create_from_api(mbid=data['id'])
assert not created
assert track == track2
def test_album_tags_deduced_from_tracks_tags(factories, django_assert_num_queries):
tag = factories['taggit.Tag']()
album = factories['music.Album']()
tracks = factories['music.Track'].create_batch(
5, album=album, tags=[tag])
album = models.Album.objects.prefetch_related('tracks__tags').get(pk=album.pk)
with django_assert_num_queries(0):
assert tag in album.tags
def test_artist_tags_deduced_from_album_tags(factories, django_assert_num_queries):
tag = factories['taggit.Tag']()
album = factories['music.Album']()
artist = album.artist
tracks = factories['music.Track'].create_batch(
5, album=album, tags=[tag])
artist = models.Artist.objects.prefetch_related('albums__tracks__tags').get(pk=artist.pk)
with django_assert_num_queries(0):
assert tag in artist.tags
def test_can_download_image_file_for_album(mocker, factories):
mocker.patch(
'funkwhale_api.musicbrainz.api.images.get_front',
return_value=binary_data)
# client._api.get_image_front('55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album = factories['music.Album'](mbid='55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album.get_image()
album.save()
assert album.cover.file.read() == binary_data

Wyświetl plik

@ -0,0 +1,65 @@
import json
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from . import data as api_data
def test_can_import_work(factories, mocker):
mocker.patch(
'funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
recording = factories['music.Track'](
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
work = models.Work.create_from_api(id=mbid)
assert work.title == 'Chop Suey!'
assert work.nature == 'song'
assert work.language == 'eng'
assert work.mbid == mbid
# a imported work should also be linked to corresponding recordings
recording.refresh_from_db()
assert recording.work == work
def test_can_get_work_from_recording(factories, mocker):
mocker.patch(
'funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['chop_suey'])
recording = factories['music.Track'](
work=None,
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
assert recording.work == None
work = recording.get_work()
assert work.title == 'Chop Suey!'
assert work.nature == 'song'
assert work.language == 'eng'
assert work.mbid == mbid
recording.refresh_from_db()
assert recording.work == work
def test_works_import_lyrics_if_any(db, mocker):
mocker.patch(
'funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
work = models.Work.create_from_api(id=mbid)
lyrics = models.Lyrics.objects.latest('id')
assert lyrics.work == work
assert lyrics.url == 'http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!'

Wyświetl plik

@ -0,0 +1,90 @@
import json
from django.urls import reverse
from funkwhale_api.musicbrainz import api
from . import data as api_data
def test_can_search_recording_in_musicbrainz_api(db, mocker, client):
mocker.patch(
'funkwhale_api.musicbrainz.api.recordings.search',
return_value=api_data.recordings['search']['brontide matador'])
query = 'brontide matador'
url = reverse('api:v1:providers:musicbrainz:search-recordings')
expected = api_data.recordings['search']['brontide matador']
response = client.get(url, data={'query': query})
assert expected == json.loads(response.content.decode('utf-8'))
def test_can_search_release_in_musicbrainz_api(db, mocker, client):
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.search',
return_value=api_data.releases['search']['brontide matador'])
query = 'brontide matador'
url = reverse('api:v1:providers:musicbrainz:search-releases')
expected = api_data.releases['search']['brontide matador']
response = client.get(url, data={'query': query})
assert expected == json.loads(response.content.decode('utf-8'))
def test_can_search_artists_in_musicbrainz_api(db, mocker, client):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.search',
return_value=api_data.artists['search']['lost fingers'])
query = 'lost fingers'
url = reverse('api:v1:providers:musicbrainz:search-artists')
expected = api_data.artists['search']['lost fingers']
response = client.get(url, data={'query': query})
assert expected == json.loads(response.content.decode('utf-8'))
def test_can_get_artist_in_musicbrainz_api(db, mocker, client):
mocker.patch(
'funkwhale_api.musicbrainz.api.artists.get',
return_value=api_data.artists['get']['lost fingers'])
uuid = 'ac16bbc0-aded-4477-a3c3-1d81693d58c9'
url = reverse('api:v1:providers:musicbrainz:artist-detail', kwargs={
'uuid': uuid,
})
response = client.get(url)
expected = api_data.artists['get']['lost fingers']
assert expected == json.loads(response.content.decode('utf-8'))
def test_can_broswe_release_group_using_musicbrainz_api(db, mocker, client):
mocker.patch(
'funkwhale_api.musicbrainz.api.release_groups.browse',
return_value=api_data.release_groups['browse']['lost fingers'])
uuid = 'ac16bbc0-aded-4477-a3c3-1d81693d58c9'
url = reverse(
'api:v1:providers:musicbrainz:release-group-browse',
kwargs={
'artist_uuid': uuid,
}
)
response = client.get(url)
expected = api_data.release_groups['browse']['lost fingers']
assert expected == json.loads(response.content.decode('utf-8'))
def test_can_broswe_releases_using_musicbrainz_api(db, mocker, client):
mocker.patch(
'funkwhale_api.musicbrainz.api.releases.browse',
return_value=api_data.releases['browse']['Lost in the 80s'])
uuid = 'f04ed607-11b7-3843-957e-503ecdd485d1'
url = reverse(
'api:v1:providers:musicbrainz:release-browse',
kwargs={
'release_group_uuid': uuid,
}
)
response = client.get(url)
expected = api_data.releases['browse']['Lost in the 80s']
assert expected == json.loads(response.content.decode('utf-8'))

Wyświetl plik

@ -0,0 +1,13 @@
from funkwhale_api.musicbrainz import client
def test_can_search_recording_in_musicbrainz_api(mocker):
r = {'hello': 'world'}
m = mocker.patch(
'funkwhale_api.musicbrainz.client._api.search_artists',
return_value=r)
assert client.api.artists.search('test') == r
# now call from cache
assert client.api.artists.search('test') == r
assert client.api.artists.search('test') == r
assert m.call_count == 1

Wyświetl plik

@ -0,0 +1,39 @@
import os
import datetime
from funkwhale_api.providers.audiofile import tasks
DATA_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'files'
)
def test_can_import_single_audio_file(db, mocker):
metadata = {
'artist': ['Test artist'],
'album': ['Test album'],
'title': ['Test track'],
'TRACKNUMBER': ['4'],
'date': ['2012-08-15'],
'musicbrainz_albumid': ['a766da8b-8336-47aa-a3ee-371cc41ccc75'],
'musicbrainz_trackid': ['bd21ac48-46d8-4e78-925f-d9cc2a294656'],
'musicbrainz_artistid': ['013c8e5b-d72a-4cd3-8dee-6c64d6125823'],
}
m1 = mocker.patch('mutagen.File', return_value=metadata)
m2 = mocker.patch(
'funkwhale_api.music.metadata.Metadata.get_file_type',
return_value='OggVorbis',
)
track_file = tasks.from_path(os.path.join(DATA_DIR, 'dummy_file.ogg'))
track = track_file.track
assert track.title == metadata['title'][0]
assert track.mbid == metadata['musicbrainz_trackid'][0]
assert track.position == 4
assert track.album.title == metadata['album'][0]
assert track.album.mbid == metadata['musicbrainz_albumid'][0]
assert track.album.release_date == datetime.date(2012, 8, 15)
assert track.artist.name == metadata['artist'][0]
assert track.artist.mbid == metadata['musicbrainz_artistid'][0]

Wyświetl plik

@ -0,0 +1,11 @@
import os
from funkwhale_api import downloader
def test_can_download_audio_from_youtube_url_to_vorbis(tmpdir):
data = downloader.download(
'https://www.youtube.com/watch?v=tPEE9ZwTmy0',
target_directory=tmpdir)
assert data['audio_file_path'] == os.path.join(tmpdir, 'tPEE9ZwTmy0.ogg')
assert os.path.exists(data['audio_file_path'])

Wyświetl plik

@ -0,0 +1,92 @@
import json
import pytest
from django.urls import reverse
from funkwhale_api.music.models import Track, Artist
from funkwhale_api.favorites.models import TrackFavorite
def test_user_can_add_favorite(factories):
track = factories['music.Track']()
user = factories['users.User']()
f = TrackFavorite.add(track, user)
assert f.track == track
assert f.user == user
def test_user_can_get_his_favorites(factories, logged_in_client, client):
favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
url = reverse('api:v1:favorites:tracks-list')
response = logged_in_client.get(url)
expected = [
{
'track': favorite.track.pk,
'id': favorite.id,
'creation_date': favorite.creation_date.isoformat().replace('+00:00', 'Z'),
}
]
parsed_json = json.loads(response.content.decode('utf-8'))
assert expected == parsed_json['results']
def test_user_can_add_favorite_via_api(factories, logged_in_client, client):
track = factories['music.Track']()
url = reverse('api:v1:favorites:tracks-list')
response = logged_in_client.post(url, {'track': track.pk})
favorite = TrackFavorite.objects.latest('id')
expected = {
'track': track.pk,
'id': favorite.id,
'creation_date': favorite.creation_date.isoformat().replace('+00:00', 'Z'),
}
parsed_json = json.loads(response.content.decode('utf-8'))
assert expected == parsed_json
assert favorite.track == track
assert favorite.user == logged_in_client.user
def test_user_can_remove_favorite_via_api(logged_in_client, factories, client):
favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
url = reverse('api:v1:favorites:tracks-detail', kwargs={'pk': favorite.pk})
response = client.delete(url, {'track': favorite.track.pk})
assert response.status_code == 204
assert TrackFavorite.objects.count() == 0
def test_user_can_remove_favorite_via_api_using_track_id(factories, logged_in_client):
favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
url = reverse('api:v1:favorites:tracks-remove')
response = logged_in_client.delete(
url, json.dumps({'track': favorite.track.pk}),
content_type='application/json'
)
assert response.status_code == 204
assert TrackFavorite.objects.count() == 0
@pytest.mark.parametrize('url,method', [
('api:v1:favorites:tracks-list', 'get'),
])
def test_url_require_auth(url, method, db, settings, client):
settings.API_AUTHENTICATION_REQUIRED = True
url = reverse(url)
response = getattr(client, method)(url)
assert response.status_code == 401
def test_can_filter_tracks_by_favorites(factories, logged_in_client):
favorite = factories['favorites.TrackFavorite'](user=logged_in_client.user)
url = reverse('api:v1:tracks-list')
response = logged_in_client.get(url, data={'favorites': True})
parsed_json = json.loads(response.content.decode('utf-8'))
assert parsed_json['count'] == 1
assert parsed_json['results'][0]['id'] == favorite.track.id

Wyświetl plik

@ -0,0 +1,42 @@
import random
import json
from django.urls import reverse
from django.core.exceptions import ValidationError
from django.utils import timezone
from funkwhale_api.history import models
def test_can_create_listening(factories):
track = factories['music.Track']()
user = factories['users.User']()
now = timezone.now()
l = models.Listening.objects.create(user=user, track=track)
def test_anonymous_user_can_create_listening_via_api(client, factories, settings):
settings.API_AUTHENTICATION_REQUIRED = False
track = factories['music.Track']()
url = reverse('api:v1:history:listenings-list')
response = client.post(url, {
'track': track.pk,
})
listening = models.Listening.objects.latest('id')
assert listening.track == track
assert listening.session_key == client.session.session_key
def test_logged_in_user_can_create_listening_via_api(logged_in_client, factories):
track = factories['music.Track']()
url = reverse('api:v1:history:listenings-list')
response = logged_in_client.post(url, {
'track': track.pk,
})
listening = models.Listening.objects.latest('id')
assert listening.track == track
assert listening.user == logged_in_client.user

Wyświetl plik

@ -0,0 +1,21 @@
from django.urls import reverse
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
def test_can_authenticate_using_token_param_in_url(factories, settings, client):
user = factories['users.User']()
settings.API_AUTHENTICATION_REQUIRED = True
url = reverse('api:v1:tracks-list')
response = client.get(url)
assert response.status_code == 401
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
response = client.get(url, data={
'jwt': token
})
assert response.status_code == 200

Wyświetl plik

@ -0,0 +1,54 @@
import json
from django.urls import reverse
from django.core.exceptions import ValidationError
from django.utils import timezone
from funkwhale_api.playlists import models
from funkwhale_api.playlists.serializers import PlaylistSerializer
def test_can_create_playlist(factories):
tracks = factories['music.Track'].create_batch(5)
playlist = factories['playlists.Playlist']()
previous = None
for track in tracks:
previous = playlist.add_track(track, previous=previous)
playlist_tracks = list(playlist.playlist_tracks.all())
previous = None
for idx, track in enumerate(tracks):
plt = playlist_tracks[idx]
assert plt.position == idx
assert plt.track == track
if previous:
assert playlist_tracks[idx + 1] == previous
assert plt.playlist == playlist
def test_can_create_playlist_via_api(logged_in_client):
url = reverse('api:v1:playlists-list')
data = {
'name': 'test',
}
response = logged_in_client.post(url, data)
playlist = logged_in_client.user.playlists.latest('id')
assert playlist.name == 'test'
def test_can_add_playlist_track_via_api(factories, logged_in_client):
tracks = factories['music.Track'].create_batch(5)
playlist = factories['playlists.Playlist'](user=logged_in_client.user)
url = reverse('api:v1:playlist-tracks-list')
data = {
'playlist': playlist.pk,
'track': tracks[0].pk
}
response = logged_in_client.post(url, data)
plts = logged_in_client.user.playlists.latest('id').playlist_tracks.all()
assert plts.first().track == tracks[0]

Wyświetl plik

@ -0,0 +1,195 @@
import json
import random
import pytest
from django.urls import reverse
from django.core.exceptions import ValidationError
from funkwhale_api.radios import radios
from funkwhale_api.radios import models
from funkwhale_api.favorites.models import TrackFavorite
def test_can_pick_track_from_choices():
choices = [1, 2, 3, 4, 5]
radio = radios.SimpleRadio()
first_pick = radio.pick(choices=choices)
assert first_pick in choices
previous_choices = [first_pick]
for remaining_choice in choices:
pick = radio.pick(choices=choices, previous_choices=previous_choices)
assert pick in set(choices).difference(previous_choices)
def test_can_pick_by_weight():
choices_with_weight = [
# choice, weight
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
]
picks = {choice: 0 for choice, weight in choices_with_weight}
for i in range(1000):
radio = radios.SimpleRadio()
pick = radio.weighted_pick(choices=choices_with_weight)
picks[pick] = picks[pick] + 1
assert picks[5] > picks[4]
assert picks[4] > picks[3]
assert picks[3] > picks[2]
assert picks[2] > picks[1]
def test_can_get_choices_for_favorites_radio(factories):
tracks = factories['music.Track'].create_batch(100)
user = factories['users.User']()
for i in range(20):
TrackFavorite.add(track=random.choice(tracks), user=user)
radio = radios.FavoritesRadio()
choices = radio.get_choices(user=user)
assert choices.count() == user.track_favorites.all().count()
for favorite in user.track_favorites.all():
assert favorite.track in choices
for i in range(20):
pick = radio.pick(user=user)
assert pick in choices
def test_can_use_radio_session_to_filter_choices(factories):
tracks = factories['music.Track'].create_batch(30)
user = factories['users.User']()
radio = radios.RandomRadio()
session = radio.start_session(user)
for i in range(30):
p = radio.pick()
# ensure 30 differents tracks have been suggested
tracks_id = [
session_track.track.pk
for session_track in session.session_tracks.all()]
assert len(set(tracks_id)) == 30
def test_can_restore_radio_from_previous_session(factories):
user = factories['users.User']()
radio = radios.RandomRadio()
session = radio.start_session(user)
restarted_radio = radios.RandomRadio(session)
assert radio.session == restarted_radio.session
def test_can_start_radio_for_logged_in_user(logged_in_client):
url = reverse('api:v1:radios:sessions-list')
response = logged_in_client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
assert session.radio_type == 'random'
assert session.user == logged_in_client.user
def test_can_start_radio_for_anonymous_user(client, db):
url = reverse('api:v1:radios:sessions-list')
response = client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
assert session.radio_type == 'random'
assert session.user is None
assert session.session_key == client.session.session_key
def test_can_get_track_for_session_from_api(factories, logged_in_client):
tracks = factories['music.Track'].create_batch(size=1)
url = reverse('api:v1:radios:sessions-list')
response = logged_in_client.post(url, {'radio_type': 'random'})
session = models.RadioSession.objects.latest('id')
url = reverse('api:v1:radios:tracks-list')
response = logged_in_client.post(url, {'session': session.pk})
data = json.loads(response.content.decode('utf-8'))
assert data['track']['id'] == tracks[0].id
assert data['position'] == 1
next_track = factories['music.Track']()
response = logged_in_client.post(url, {'session': session.pk})
data = json.loads(response.content.decode('utf-8'))
assert data['track']['id'] == next_track.id
assert data['position'] == 2
def test_related_object_radio_validate_related_object(factories):
user = factories['users.User']()
# cannot start without related object
radio = radios.ArtistRadio()
with pytest.raises(ValidationError):
radio.start_session(user)
# cannot start with bad related object type
radio = radios.ArtistRadio()
with pytest.raises(ValidationError):
radio.start_session(user, related_object=user)
def test_can_start_artist_radio(factories):
user = factories['users.User']()
artist = factories['music.Artist']()
wrong_tracks = factories['music.Track'].create_batch(5)
good_tracks = factories['music.Track'].create_batch(5, artist=artist)
radio = radios.ArtistRadio()
session = radio.start_session(user, related_object=artist)
assert session.radio_type == 'artist'
for i in range(5):
assert radio.pick() in good_tracks
def test_can_start_tag_radio(factories):
user = factories['users.User']()
tag = factories['taggit.Tag']()
wrong_tracks = factories['music.Track'].create_batch(5)
good_tracks = factories['music.Track'].create_batch(5, tags=[tag])
radio = radios.TagRadio()
session = radio.start_session(user, related_object=tag)
assert session.radio_type =='tag'
for i in range(5):
assert radio.pick() in good_tracks
def test_can_start_artist_radio_from_api(client, factories):
artist = factories['music.Artist']()
url = reverse('api:v1:radios:sessions-list')
response = client.post(
url, {'radio_type': 'artist', 'related_object_id': artist.id})
session = models.RadioSession.objects.latest('id')
assert session.radio_type, 'artist'
assert session.related_object, artist
def test_can_start_less_listened_radio(factories):
user = factories['users.User']()
history = factories['history.Listening'].create_batch(5, user=user)
wrong_tracks = [h.track for h in history]
good_tracks = factories['music.Track'].create_batch(size=5)
radio = radios.LessListenedRadio()
session = radio.start_session(user)
assert session.related_object == user
for i in range(5):
assert radio.pick() in good_tracks

Wyświetl plik

@ -0,0 +1,95 @@
import json
from collections import OrderedDict
from django.urls import reverse
from funkwhale_api.providers.youtube.client import client
from .data import youtube as api_data
def test_can_get_search_results_from_youtube(mocker):
mocker.patch(
'funkwhale_api.providers.youtube.client._do_search',
return_value=api_data.search['8 bit adventure'])
query = '8 bit adventure'
results = client.search(query)
assert results[0]['id']['videoId'] == '0HxZn6CzOIo'
assert results[0]['snippet']['title'] == 'AdhesiveWombat - 8 Bit Adventure'
assert results[0]['full_url'] == 'https://www.youtube.com/watch?v=0HxZn6CzOIo'
def test_can_get_search_results_from_funkwhale(mocker, client, db):
mocker.patch(
'funkwhale_api.providers.youtube.client._do_search',
return_value=api_data.search['8 bit adventure'])
query = '8 bit adventure'
url = reverse('api:v1:providers:youtube:search')
response = client.get(url, {'query': query})
# we should cast the youtube result to something more generic
expected = {
"id": "0HxZn6CzOIo",
"url": "https://www.youtube.com/watch?v=0HxZn6CzOIo",
"type": "youtube#video",
"description": "Make sure to apply adhesive evenly before use. GET IT HERE: http://adhesivewombat.bandcamp.com/album/marsupial-madness Facebook: ...",
"channelId": "UCps63j3krzAG4OyXeEyuhFw",
"title": "AdhesiveWombat - 8 Bit Adventure",
"channelTitle": "AdhesiveWombat",
"publishedAt": "2012-08-22T18:41:03.000Z",
"cover": "https://i.ytimg.com/vi/0HxZn6CzOIo/hqdefault.jpg"
}
assert json.loads(response.content.decode('utf-8'))[0] == expected
def test_can_send_multiple_queries_at_once(mocker):
mocker.patch(
'funkwhale_api.providers.youtube.client._do_search',
side_effect=[
api_data.search['8 bit adventure'],
api_data.search['system of a down toxicity'],
]
)
queries = OrderedDict()
queries['1'] = {
'q': '8 bit adventure',
}
queries['2'] = {
'q': 'system of a down toxicity',
}
results = client.search_multiple(queries)
assert results['1'][0]['id']['videoId'] == '0HxZn6CzOIo'
assert results['1'][0]['snippet']['title'] == 'AdhesiveWombat - 8 Bit Adventure'
assert results['1'][0]['full_url'] == 'https://www.youtube.com/watch?v=0HxZn6CzOIo'
assert results['2'][0]['id']['videoId'] == 'BorYwGi2SJc'
assert results['2'][0]['snippet']['title'] == 'System of a Down: Toxicity'
assert results['2'][0]['full_url'] == 'https://www.youtube.com/watch?v=BorYwGi2SJc'
def test_can_send_multiple_queries_at_once_from_funwkhale(mocker, db, client):
mocker.patch(
'funkwhale_api.providers.youtube.client._do_search',
return_value=api_data.search['8 bit adventure'])
queries = OrderedDict()
queries['1'] = {
'q': '8 bit adventure',
}
expected = {
"id": "0HxZn6CzOIo",
"url": "https://www.youtube.com/watch?v=0HxZn6CzOIo",
"type": "youtube#video",
"description": "Make sure to apply adhesive evenly before use. GET IT HERE: http://adhesivewombat.bandcamp.com/album/marsupial-madness Facebook: ...",
"channelId": "UCps63j3krzAG4OyXeEyuhFw",
"title": "AdhesiveWombat - 8 Bit Adventure",
"channelTitle": "AdhesiveWombat",
"publishedAt": "2012-08-22T18:41:03.000Z",
"cover": "https://i.ytimg.com/vi/0HxZn6CzOIo/hqdefault.jpg"
}
url = reverse('api:v1:providers:youtube:searchs')
response = client.post(
url, json.dumps(queries), content_type='application/json')
assert expected == json.loads(response.content.decode('utf-8'))['1'][0]

Wyświetl plik

@ -0,0 +1,35 @@
from funkwhale_api.users.admin import MyUserCreationForm
def test_clean_username_success(db):
# Instantiate the form with a new username
form = MyUserCreationForm({
'username': 'alamode',
'password1': '123456',
'password2': '123456',
})
# Run is_valid() to trigger the validation
valid = form.is_valid()
assert valid
# Run the actual clean_username method
username = form.clean_username()
assert 'alamode' == username
def test_clean_username_false(factories):
user = factories['users.User']()
# Instantiate the form with the same username as self.user
form = MyUserCreationForm({
'username': user.username,
'password1': '123456',
'password2': '123456',
})
# Run is_valid() to trigger the validation, which is going to fail
# because the username is already taken
valid = form.is_valid()
assert not valid
# The form.errors dict should contain a single error called 'username'
assert len(form.errors) == 1
assert 'username' in form.errors

Wyświetl plik

@ -0,0 +1,4 @@
def test__str__(factories):
user = factories['users.User'](username='hello')
assert user.__str__() == 'hello'

Wyświetl plik

@ -0,0 +1,64 @@
import json
from django.test import RequestFactory
from django.urls import reverse
from funkwhale_api.users.models import User
def test_can_create_user_via_api(settings, client, db):
url = reverse('rest_register')
data = {
'username': 'test1',
'email': 'test1@test.com',
'password1': 'testtest',
'password2': 'testtest',
}
settings.REGISTRATION_MODE = "public"
response = client.post(url, data)
assert response.status_code == 201
u = User.objects.get(email='test1@test.com')
assert u.username == 'test1'
def test_can_disable_registration_view(settings, client, db):
url = reverse('rest_register')
data = {
'username': 'test1',
'email': 'test1@test.com',
'password1': 'testtest',
'password2': 'testtest',
}
settings.REGISTRATION_MODE = "disabled"
response = client.post(url, data)
assert response.status_code == 403
def test_can_fetch_data_from_api(client, factories):
url = reverse('api:v1:users:users-me')
response = client.get(url)
# login required
assert response.status_code == 401
user = factories['users.User'](
is_staff=True,
perms=[
'music.add_importbatch',
'dynamic_preferences.change_globalpreferencemodel',
]
)
assert user.has_perm('music.add_importbatch')
client.login(username=user.username, password='test')
response = client.get(url)
assert response.status_code == 200
payload = json.loads(response.content.decode('utf-8'))
assert payload['username'] == user.username
assert payload['is_staff'] == user.is_staff
assert payload['is_superuser'] == user.is_superuser
assert payload['email'] == user.email
assert payload['name'] == user.name
assert payload['permissions']['import.launch']['status']
assert payload['permissions']['settings.change']['status']