mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-05 07:49:23 +02:00
Fixed #54: Now use pytest everywhere \o/
This commit is contained in:
parent
a7758395ee
commit
099cdfa99c
65 changed files with 1466 additions and 1467 deletions
|
@ -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)
|
|
@ -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']))
|
30
api/funkwhale_api/factories.py
Normal file
30
api/funkwhale_api/factories.py
Normal file
|
@ -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
|
15
api/funkwhale_api/favorites/factories.py
Normal file
15
api/funkwhale_api/favorites/factories.py
Normal file
|
@ -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'
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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')
|
File diff suppressed because one or more lines are too long
|
@ -1,502 +0,0 @@
|
|||
artists = {'search': {}, 'get': {}}
|
||||
artists['search']['adhesive_wombat'] = {
|
||||
'artist-list': [
|
||||
{
|
||||
'type': 'Person',
|
||||
'ext:score': '100',
|
||||
'id': '62c3befb-6366-4585-b256-809472333801',
|
||||
'disambiguation': 'George Shaw',
|
||||
'gender': 'male',
|
||||
'area': {'sort-name': 'Raleigh', 'id': '3f8828b9-ba93-4604-9b92-1f616fa1abd1', 'name': 'Raleigh'},
|
||||
'sort-name': 'Wombat, Adhesive',
|
||||
'life-span': {'ended': 'false'},
|
||||
'name': 'Adhesive Wombat'
|
||||
},
|
||||
{
|
||||
'country': 'SE',
|
||||
'type': 'Group',
|
||||
'ext:score': '42',
|
||||
'id': '61b34e69-7573-4208-bc89-7061bca5a8fc',
|
||||
'area': {'sort-name': 'Sweden', 'id': '23d10872-f5ae-3f0c-bf55-332788a16ecb', 'name': 'Sweden'},
|
||||
'sort-name': 'Adhesive',
|
||||
'life-span': {'end': '2002-07-12', 'begin': '1994', 'ended': 'true'},
|
||||
'name': 'Adhesive',
|
||||
'begin-area': {
|
||||
'sort-name': 'Katrineholm',
|
||||
'id': '02390d96-b5a3-4282-a38f-e64a95d08b7f',
|
||||
'name': 'Katrineholm'
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
artists['get']['adhesive_wombat'] = {'artist': artists['search']['adhesive_wombat']['artist-list'][0]}
|
||||
|
||||
artists['get']['soad'] = {
|
||||
'artist': {
|
||||
'country': 'US',
|
||||
'isni-list': ['0000000121055332'],
|
||||
'type': 'Group',
|
||||
'area': {
|
||||
'iso-3166-1-code-list': ['US'],
|
||||
'sort-name': 'United States',
|
||||
'id': '489ce91b-6658-3307-9877-795b68554c98',
|
||||
'name': 'United States'
|
||||
},
|
||||
'begin-area': {
|
||||
'sort-name': 'Glendale',
|
||||
'id': '6db2e45d-d7f3-43da-ac0b-7ba5ca627373',
|
||||
'name': 'Glendale'
|
||||
},
|
||||
'id': 'cc0b7089-c08d-4c10-b6b0-873582c17fd6',
|
||||
'life-span': {'begin': '1994'},
|
||||
'sort-name': 'System of a Down',
|
||||
'name': 'System of a Down'
|
||||
}
|
||||
}
|
||||
|
||||
albums = {'search': {}, 'get': {}, 'get_with_includes': {}}
|
||||
albums['search']['hypnotize'] = {
|
||||
'release-list': [
|
||||
{
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"alias-list": [
|
||||
{
|
||||
"alias": "SoaD",
|
||||
"sort-name": "SoaD",
|
||||
"type": "Search hint"
|
||||
},
|
||||
{
|
||||
"alias": "S.O.A.D.",
|
||||
"sort-name": "S.O.A.D.",
|
||||
"type": "Search hint"
|
||||
},
|
||||
{
|
||||
"alias": "System Of Down",
|
||||
"sort-name": "System Of Down",
|
||||
"type": "Search hint"
|
||||
}
|
||||
],
|
||||
"id": "cc0b7089-c08d-4c10-b6b0-873582c17fd6",
|
||||
"name": "System of a Down",
|
||||
"sort-name": "System of a Down"
|
||||
}
|
||||
}
|
||||
],
|
||||
"artist-credit-phrase": "System of a Down",
|
||||
"barcode": "",
|
||||
"country": "US",
|
||||
"date": "2005",
|
||||
"ext:score": "100",
|
||||
"id": "47ae093f-1607-49a3-be11-a15d335ccc94",
|
||||
"label-info-list": [
|
||||
{
|
||||
"catalog-number": "8-2796-93871-2",
|
||||
"label": {
|
||||
"id": "f5be9cfe-e1af-405c-a074-caeaed6797c0",
|
||||
"name": "American Recordings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"catalog-number": "D162990",
|
||||
"label": {
|
||||
"id": "9a7d39a4-a887-40f3-a645-a9a136d1f13f",
|
||||
"name": "BMG Direct Marketing, Inc."
|
||||
}
|
||||
}
|
||||
],
|
||||
"medium-count": 1,
|
||||
"medium-list": [
|
||||
{
|
||||
"disc-count": 1,
|
||||
"disc-list": [],
|
||||
"format": "CD",
|
||||
"track-count": 12,
|
||||
"track-list": []
|
||||
}
|
||||
],
|
||||
"medium-track-count": 12,
|
||||
"packaging": "Digipak",
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"id": "489ce91b-6658-3307-9877-795b68554c98",
|
||||
"iso-3166-1-code-list": [
|
||||
"US"
|
||||
],
|
||||
"name": "United States",
|
||||
"sort-name": "United States"
|
||||
},
|
||||
"date": "2005"
|
||||
}
|
||||
],
|
||||
"release-group": {
|
||||
"id": "72035143-d6ec-308b-8ee5-070b8703902a",
|
||||
"primary-type": "Album",
|
||||
"type": "Album"
|
||||
},
|
||||
"status": "Official",
|
||||
"text-representation": {
|
||||
"language": "eng",
|
||||
"script": "Latn"
|
||||
},
|
||||
"title": "Hypnotize"
|
||||
},
|
||||
{
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"alias-list": [
|
||||
{
|
||||
"alias": "SoaD",
|
||||
"sort-name": "SoaD",
|
||||
"type": "Search hint"
|
||||
},
|
||||
{
|
||||
"alias": "S.O.A.D.",
|
||||
"sort-name": "S.O.A.D.",
|
||||
"type": "Search hint"
|
||||
},
|
||||
{
|
||||
"alias": "System Of Down",
|
||||
"sort-name": "System Of Down",
|
||||
"type": "Search hint"
|
||||
}
|
||||
],
|
||||
"id": "cc0b7089-c08d-4c10-b6b0-873582c17fd6",
|
||||
"name": "System of a Down",
|
||||
"sort-name": "System of a Down"
|
||||
}
|
||||
}
|
||||
],
|
||||
"artist-credit-phrase": "System of a Down",
|
||||
"asin": "B000C6NRY8",
|
||||
"barcode": "827969387115",
|
||||
"country": "US",
|
||||
"date": "2005-12-20",
|
||||
"ext:score": "100",
|
||||
"id": "8a4034a9-7834-3b7e-a6f0-d0791e3731fb",
|
||||
"medium-count": 1,
|
||||
"medium-list": [
|
||||
{
|
||||
"disc-count": 0,
|
||||
"disc-list": [],
|
||||
"format": "Vinyl",
|
||||
"track-count": 12,
|
||||
"track-list": []
|
||||
}
|
||||
],
|
||||
"medium-track-count": 12,
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"id": "489ce91b-6658-3307-9877-795b68554c98",
|
||||
"iso-3166-1-code-list": [
|
||||
"US"
|
||||
],
|
||||
"name": "United States",
|
||||
"sort-name": "United States"
|
||||
},
|
||||
"date": "2005-12-20"
|
||||
}
|
||||
],
|
||||
"release-group": {
|
||||
"id": "72035143-d6ec-308b-8ee5-070b8703902a",
|
||||
"primary-type": "Album",
|
||||
"type": "Album"
|
||||
},
|
||||
"status": "Official",
|
||||
"text-representation": {
|
||||
"language": "eng",
|
||||
"script": "Latn"
|
||||
},
|
||||
"title": "Hypnotize"
|
||||
},
|
||||
]
|
||||
}
|
||||
albums['get']['hypnotize'] = {'release': albums['search']['hypnotize']['release-list'][0]}
|
||||
albums['get_with_includes']['hypnotize'] = {
|
||||
'release': {
|
||||
'artist-credit': [
|
||||
{'artist': {'id': 'cc0b7089-c08d-4c10-b6b0-873582c17fd6',
|
||||
'name': 'System of a Down',
|
||||
'sort-name': 'System of a Down'}}],
|
||||
'artist-credit-phrase': 'System of a Down',
|
||||
'barcode': '',
|
||||
'country': 'US',
|
||||
'cover-art-archive': {'artwork': 'true',
|
||||
'back': 'false',
|
||||
'count': '1',
|
||||
'front': 'true'},
|
||||
'date': '2005',
|
||||
'id': '47ae093f-1607-49a3-be11-a15d335ccc94',
|
||||
'medium-count': 1,
|
||||
'medium-list': [{'format': 'CD',
|
||||
'position': '1',
|
||||
'track-count': 12,
|
||||
'track-list': [{'id': '59f5cf9a-75b2-3aa3-abda-6807a87107b3',
|
||||
'length': '186000',
|
||||
'number': '1',
|
||||
'position': '1',
|
||||
'recording': {'id': '76d03fc5-758c-48d0-a354-a67de086cc68',
|
||||
'length': '186000',
|
||||
'title': 'Attack'},
|
||||
'track_or_recording_length': '186000'},
|
||||
{'id': '3aaa28c1-12b1-3c2a-b90a-82e09e355608',
|
||||
'length': '239000',
|
||||
'number': '2',
|
||||
'position': '2',
|
||||
'recording': {'id': '327543b0-9193-48c5-83c9-01c7b36c8c0a',
|
||||
'length': '239000',
|
||||
'title': 'Dreaming'},
|
||||
'track_or_recording_length': '239000'},
|
||||
{'id': 'a34fef19-e637-3436-b7eb-276ff2814d6f',
|
||||
'length': '147000',
|
||||
'number': '3',
|
||||
'position': '3',
|
||||
'recording': {'id': '6e27866c-07a1-425d-bb4f-9d9e728db344',
|
||||
'length': '147000',
|
||||
'title': 'Kill Rock ’n Roll'},
|
||||
'track_or_recording_length': '147000'},
|
||||
{'id': '72a4e5c0-c150-3ba1-9ceb-3ab82648af25',
|
||||
'length': '189000',
|
||||
'number': '4',
|
||||
'position': '4',
|
||||
'recording': {'id': '7ff8a67d-c8e2-4b3a-a045-7ad3561d0605',
|
||||
'length': '189000',
|
||||
'title': 'Hypnotize'},
|
||||
'track_or_recording_length': '189000'},
|
||||
{'id': 'a748fa6e-b3b7-3b22-89fb-a038ec92ac32',
|
||||
'length': '178000',
|
||||
'number': '5',
|
||||
'position': '5',
|
||||
'recording': {'id': '19b6eb6a-0e76-4ef7-b63f-959339dbd5d2',
|
||||
'length': '178000',
|
||||
'title': 'Stealing Society'},
|
||||
'track_or_recording_length': '178000'},
|
||||
{'id': '5c5a8d4e-e21a-317e-a719-6e2dbdefa5d2',
|
||||
'length': '216000',
|
||||
'number': '6',
|
||||
'position': '6',
|
||||
'recording': {'id': 'c3c2afe1-ee9a-47cb-b3c6-ff8100bc19d5',
|
||||
'length': '216000',
|
||||
'title': 'Tentative'},
|
||||
'track_or_recording_length': '216000'},
|
||||
{'id': '265718ba-787f-3193-947b-3b6fa69ffe96',
|
||||
'length': '175000',
|
||||
'number': '7',
|
||||
'position': '7',
|
||||
'recording': {'id': '96f804e1-f600-4faa-95a6-ce597e7db120',
|
||||
'length': '175000',
|
||||
'title': 'U‐Fig'},
|
||||
'title': 'U-Fig',
|
||||
'track_or_recording_length': '175000'},
|
||||
{'id': 'cdcf8572-3060-31ca-a72c-1ded81ca1f7a',
|
||||
'length': '328000',
|
||||
'number': '8',
|
||||
'position': '8',
|
||||
'recording': {'id': '26ba38f0-b26b-48b7-8e77-226b22a55f79',
|
||||
'length': '328000',
|
||||
'title': 'Holy Mountains'},
|
||||
'track_or_recording_length': '328000'},
|
||||
{'id': 'f9f00cb0-5635-3217-a2a0-bd61917eb0df',
|
||||
'length': '171000',
|
||||
'number': '9',
|
||||
'position': '9',
|
||||
'recording': {'id': '039f3379-3a69-4e75-a882-df1c4e1608aa',
|
||||
'length': '171000',
|
||||
'title': 'Vicinity of Obscenity'},
|
||||
'track_or_recording_length': '171000'},
|
||||
{'id': 'cdd45914-6741-353e-bbb5-d281048ff24f',
|
||||
'length': '164000',
|
||||
'number': '10',
|
||||
'position': '10',
|
||||
'recording': {'id': 'c24d541a-a9a8-4a22-84c6-5e6419459cf8',
|
||||
'length': '164000',
|
||||
'title': 'She’s Like Heroin'},
|
||||
'track_or_recording_length': '164000'},
|
||||
{'id': 'cfcf12ac-6831-3dd6-a2eb-9d0bfeee3f6d',
|
||||
'length': '167000',
|
||||
'number': '11',
|
||||
'position': '11',
|
||||
'recording': {'id': '0aff4799-849f-4f83-84f4-22cabbba2378',
|
||||
'length': '167000',
|
||||
'title': 'Lonely Day'},
|
||||
'track_or_recording_length': '167000'},
|
||||
{'id': '7e38bb38-ff62-3e41-a670-b7d77f578a1f',
|
||||
'length': '220000',
|
||||
'number': '12',
|
||||
'position': '12',
|
||||
'recording': {'id': 'e1b4d90f-2f44-4fe6-a826-362d4e3d9b88',
|
||||
'length': '220000',
|
||||
'title': 'Soldier Side'},
|
||||
'track_or_recording_length': '220000'}]}],
|
||||
'packaging': 'Digipak',
|
||||
'quality': 'normal',
|
||||
'release-event-count': 1,
|
||||
'release-event-list': [{'area': {'id': '489ce91b-6658-3307-9877-795b68554c98',
|
||||
'iso-3166-1-code-list': ['US'],
|
||||
'name': 'United States',
|
||||
'sort-name': 'United States'},
|
||||
'date': '2005'}],
|
||||
'status': 'Official',
|
||||
'text-representation': {'language': 'eng', 'script': 'Latn'},
|
||||
'title': 'Hypnotize'}}
|
||||
|
||||
albums['get']['marsupial'] = {
|
||||
'release': {
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"disambiguation": "George Shaw",
|
||||
"id": "62c3befb-6366-4585-b256-809472333801",
|
||||
"name": "Adhesive Wombat",
|
||||
"sort-name": "Wombat, Adhesive"
|
||||
}
|
||||
}
|
||||
],
|
||||
"artist-credit-phrase": "Adhesive Wombat",
|
||||
"country": "XW",
|
||||
"cover-art-archive": {
|
||||
"artwork": "true",
|
||||
"back": "false",
|
||||
"count": "1",
|
||||
"front": "true"
|
||||
},
|
||||
"date": "2013-06-05",
|
||||
"id": "a50d2a81-2a50-484d-9cb4-b9f6833f583e",
|
||||
"packaging": "None",
|
||||
"quality": "normal",
|
||||
"release-event-count": 1,
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"id": "525d4e18-3d00-31b9-a58b-a146a916de8f",
|
||||
"iso-3166-1-code-list": [
|
||||
"XW"
|
||||
],
|
||||
"name": "[Worldwide]",
|
||||
"sort-name": "[Worldwide]"
|
||||
},
|
||||
"date": "2013-06-05"
|
||||
}
|
||||
],
|
||||
"status": "Official",
|
||||
"text-representation": {
|
||||
"language": "eng",
|
||||
"script": "Latn"
|
||||
},
|
||||
"title": "Marsupial Madness"
|
||||
}
|
||||
}
|
||||
|
||||
tracks = {'search': {}, 'get': {}}
|
||||
|
||||
tracks['search']['8bitadventures'] = {
|
||||
'recording-list': [
|
||||
{
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"disambiguation": "George Shaw",
|
||||
"id": "62c3befb-6366-4585-b256-809472333801",
|
||||
"name": "Adhesive Wombat",
|
||||
"sort-name": "Wombat, Adhesive"
|
||||
}
|
||||
}
|
||||
],
|
||||
"artist-credit-phrase": "Adhesive Wombat",
|
||||
"ext:score": "100",
|
||||
"id": "9968a9d6-8d92-4051-8f76-674e157b6eed",
|
||||
"length": "271000",
|
||||
"release-list": [
|
||||
{
|
||||
"country": "XW",
|
||||
"date": "2013-06-05",
|
||||
"id": "a50d2a81-2a50-484d-9cb4-b9f6833f583e",
|
||||
"medium-list": [
|
||||
{
|
||||
"format": "Digital Media",
|
||||
"position": "1",
|
||||
"track-count": 11,
|
||||
"track-list": [
|
||||
{
|
||||
"id": "64d43604-c1ee-4f45-a02c-030672d2fe27",
|
||||
"length": "271000",
|
||||
"number": "1",
|
||||
"title": "8-Bit Adventure",
|
||||
"track_or_recording_length": "271000"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"medium-track-count": 11,
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"id": "525d4e18-3d00-31b9-a58b-a146a916de8f",
|
||||
"iso-3166-1-code-list": [
|
||||
"XW"
|
||||
],
|
||||
"name": "[Worldwide]",
|
||||
"sort-name": "[Worldwide]"
|
||||
},
|
||||
"date": "2013-06-05"
|
||||
}
|
||||
],
|
||||
"release-group": {
|
||||
"id": "447b4979-2178-405c-bfe6-46bf0b09e6c7",
|
||||
"primary-type": "Album",
|
||||
"type": "Album"
|
||||
},
|
||||
"status": "Official",
|
||||
"title": "Marsupial Madness"
|
||||
}
|
||||
],
|
||||
"title": "8-Bit Adventure",
|
||||
"tag-list": [
|
||||
{
|
||||
"count": "2",
|
||||
"name": "techno"
|
||||
},
|
||||
{
|
||||
"count": "2",
|
||||
"name": "good-music"
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
tracks['get']['8bitadventures'] = {'recording': tracks['search']['8bitadventures']['recording-list'][0]}
|
||||
tracks['get']['chop_suey'] = {
|
||||
'recording': {
|
||||
'id': '46c7368a-013a-47b6-97cc-e55e7ab25213',
|
||||
'length': '210240',
|
||||
'title': 'Chop Suey!',
|
||||
'work-relation-list': [{'target': 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5',
|
||||
'type': 'performance',
|
||||
'type-id': 'a3005666-a872-32c3-ad06-98af558e99b0',
|
||||
'work': {'id': 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5',
|
||||
'language': 'eng',
|
||||
'title': 'Chop Suey!'}}]}}
|
||||
|
||||
works = {'search': {}, 'get': {}}
|
||||
works['get']['chop_suey'] = {'work': {'id': 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5',
|
||||
'language': 'eng',
|
||||
'recording-relation-list': [{'direction': 'backward',
|
||||
'recording': {'disambiguation': 'edit',
|
||||
'id': '07ca77cf-f513-4e9c-b190-d7e24bbad448',
|
||||
'length': '170893',
|
||||
'title': 'Chop Suey!'},
|
||||
'target': '07ca77cf-f513-4e9c-b190-d7e24bbad448',
|
||||
'type': 'performance',
|
||||
'type-id': 'a3005666-a872-32c3-ad06-98af558e99b0'},
|
||||
],
|
||||
'title': 'Chop Suey!',
|
||||
'type': 'Song',
|
||||
'url-relation-list': [{'direction': 'backward',
|
||||
'target': 'http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!',
|
||||
'type': 'lyrics',
|
||||
'type-id': 'e38e65aa-75e0-42ba-ace0-072aeb91a538'}]}}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
@ -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)
|
||||
)
|
|
@ -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)
|
|
@ -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')
|
|
@ -1,51 +0,0 @@
|
|||
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()
|
||||
assert album.release_group_id is not None
|
||||
|
||||
|
||||
def test_import_album_stores_release_group(db):
|
||||
|
||||
album_data = {
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"disambiguation": "George Shaw",
|
||||
"id": "62c3befb-6366-4585-b256-809472333801",
|
||||
"name": "Adhesive Wombat",
|
||||
"sort-name": "Wombat, Adhesive"
|
||||
}
|
||||
}
|
||||
],
|
||||
"artist-credit-phrase": "Adhesive Wombat",
|
||||
"country": "XW",
|
||||
"date": "2013-06-05",
|
||||
"id": "a50d2a81-2a50-484d-9cb4-b9f6833f583e",
|
||||
"status": "Official",
|
||||
"title": "Marsupial Madness",
|
||||
'release-group': {'id': '447b4979-2178-405c-bfe6-46bf0b09e6c7'}
|
||||
}
|
||||
artist = factories.ArtistFactory(
|
||||
mbid=album_data['artist-credit'][0]['artist']['id']
|
||||
)
|
||||
cleaned_data = models.Album.clean_musicbrainz_data(album_data)
|
||||
album = importers.load(models.Album, cleaned_data, album_data, import_hooks=[])
|
||||
|
||||
assert album.release_group_id == album_data['release-group']['id']
|
||||
assert album.artist == artist
|
||||
|
||||
|
||||
def test_import_job_is_bound_to_track_file(db, mocker):
|
||||
track = factories.TrackFactory()
|
||||
job = factories.ImportJobFactory(mbid=track.mbid)
|
||||
|
||||
mocker.patch('funkwhale_api.music.models.TrackFile.download_file')
|
||||
job.run()
|
||||
job.refresh_from_db()
|
||||
assert job.track_file.track == track
|
|
@ -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)
|
|
@ -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!')
|
|
@ -1,478 +0,0 @@
|
|||
artists = {'search': {}, 'get': {}}
|
||||
artists['search']['lost fingers'] = {
|
||||
'artist-count': 696,
|
||||
'artist-list': [
|
||||
{
|
||||
'country': 'CA',
|
||||
'sort-name': 'Lost Fingers, The',
|
||||
'id': 'ac16bbc0-aded-4477-a3c3-1d81693d58c9',
|
||||
'type': 'Group',
|
||||
'life-span': {
|
||||
'ended': 'false',
|
||||
'begin': '2008'
|
||||
},
|
||||
'area': {
|
||||
'sort-name': 'Canada',
|
||||
'id': '71bbafaa-e825-3e15-8ca9-017dcad1748b',
|
||||
'name': 'Canada'
|
||||
},
|
||||
'ext:score': '100',
|
||||
'name': 'The Lost Fingers'
|
||||
},
|
||||
]
|
||||
}
|
||||
artists['get']['lost fingers'] = {
|
||||
"artist": {
|
||||
"life-span": {
|
||||
"begin": "2008"
|
||||
},
|
||||
"type": "Group",
|
||||
"id": "ac16bbc0-aded-4477-a3c3-1d81693d58c9",
|
||||
"release-group-count": 8,
|
||||
"name": "The Lost Fingers",
|
||||
"release-group-list": [
|
||||
{
|
||||
"title": "Gypsy Kameleon",
|
||||
"first-release-date": "2010",
|
||||
"type": "Album",
|
||||
"id": "03d3f1d4-e2b0-40d3-8314-05f1896e93a0",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
{
|
||||
"title": "Gitan Kameleon",
|
||||
"first-release-date": "2011-11-11",
|
||||
"type": "Album",
|
||||
"id": "243c0cd2-2492-4f5d-bf37-c7c76bed05b7",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
{
|
||||
"title": "Pump Up the Jam \u2013 Do Not Cover, Pt. 3",
|
||||
"first-release-date": "2014-03-17",
|
||||
"type": "Single",
|
||||
"id": "4429befd-ff45-48eb-a8f4-cdf7bf007f3f",
|
||||
"primary-type": "Single"
|
||||
},
|
||||
{
|
||||
"title": "La Marquise",
|
||||
"first-release-date": "2012-03-27",
|
||||
"type": "Album",
|
||||
"id": "4dab4b96-0a6b-4507-a31e-2189e3e7bad1",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
{
|
||||
"title": "Christmas Caravan",
|
||||
"first-release-date": "2016-11-11",
|
||||
"type": "Album",
|
||||
"id": "ca0a506d-6ba9-47c3-a712-de5ce9ae6b1f",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
{
|
||||
"title": "Rendez-vous rose",
|
||||
"first-release-date": "2009-06-16",
|
||||
"type": "Album",
|
||||
"id": "d002f1a8-5890-4188-be58-1caadbbd767f",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
{
|
||||
"title": "Wonders of the World",
|
||||
"first-release-date": "2014-05-06",
|
||||
"type": "Album",
|
||||
"id": "eeb644c2-5000-42fb-b959-e5e9cc2901c5",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
{
|
||||
"title": "Lost in the 80s",
|
||||
"first-release-date": "2008-05-06",
|
||||
"type": "Album",
|
||||
"id": "f04ed607-11b7-3843-957e-503ecdd485d1",
|
||||
"primary-type": "Album"
|
||||
}
|
||||
],
|
||||
"area": {
|
||||
"iso-3166-1-code-list": [
|
||||
"CA"
|
||||
],
|
||||
"name": "Canada",
|
||||
"id": "71bbafaa-e825-3e15-8ca9-017dcad1748b",
|
||||
"sort-name": "Canada"
|
||||
},
|
||||
"sort-name": "Lost Fingers, The",
|
||||
"country": "CA"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
release_groups = {'browse': {}}
|
||||
release_groups['browse']["lost fingers"] = {
|
||||
"release-group-list": [
|
||||
{
|
||||
"first-release-date": "2010",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "Gypsy Kameleon",
|
||||
"id": "03d3f1d4-e2b0-40d3-8314-05f1896e93a0"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2011-11-11",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "Gitan Kameleon",
|
||||
"id": "243c0cd2-2492-4f5d-bf37-c7c76bed05b7"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2014-03-17",
|
||||
"type": "Single",
|
||||
"primary-type": "Single",
|
||||
"title": "Pump Up the Jam \u2013 Do Not Cover, Pt. 3",
|
||||
"id": "4429befd-ff45-48eb-a8f4-cdf7bf007f3f"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2012-03-27",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "La Marquise",
|
||||
"id": "4dab4b96-0a6b-4507-a31e-2189e3e7bad1"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2016-11-11",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "Christmas Caravan",
|
||||
"id": "ca0a506d-6ba9-47c3-a712-de5ce9ae6b1f"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2009-06-16",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "Rendez-vous rose",
|
||||
"id": "d002f1a8-5890-4188-be58-1caadbbd767f"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2014-05-06",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "Wonders of the World",
|
||||
"id": "eeb644c2-5000-42fb-b959-e5e9cc2901c5"
|
||||
},
|
||||
{
|
||||
"first-release-date": "2008-05-06",
|
||||
"type": "Album",
|
||||
"primary-type": "Album",
|
||||
"title": "Lost in the 80s",
|
||||
"id": "f04ed607-11b7-3843-957e-503ecdd485d1"
|
||||
}
|
||||
],
|
||||
"release-group-count": 8
|
||||
}
|
||||
|
||||
recordings = {'search': {}, 'get': {}}
|
||||
recordings['search']['brontide matador'] = {
|
||||
"recording-count": 1044,
|
||||
"recording-list": [
|
||||
{
|
||||
"ext:score": "100",
|
||||
"length": "366280",
|
||||
"release-list": [
|
||||
{
|
||||
"date": "2011-05-30",
|
||||
"medium-track-count": 8,
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"name": "United Kingdom",
|
||||
"sort-name": "United Kingdom",
|
||||
"id": "8a754a16-0027-3a29-b6d7-2b40ea0481ed",
|
||||
"iso-3166-1-code-list": ["GB"]
|
||||
},
|
||||
"date": "2011-05-30"
|
||||
}
|
||||
],
|
||||
"country": "GB",
|
||||
"title": "Sans Souci",
|
||||
"status": "Official",
|
||||
"id": "fde538c8-ffef-47c6-9b5a-bd28f4070e5c",
|
||||
"release-group": {
|
||||
"type": "Album",
|
||||
"id": "113ab958-cfb8-4782-99af-639d4d9eae8d",
|
||||
"primary-type": "Album"
|
||||
},
|
||||
"medium-list": [
|
||||
{
|
||||
"format": "CD",
|
||||
"track-list": [
|
||||
{
|
||||
"track_or_recording_length": "366280",
|
||||
"id": "fe506782-a5cb-3d89-9b3e-86287be05768",
|
||||
"length": "366280",
|
||||
"title": "Matador", "number": "1"
|
||||
}
|
||||
],
|
||||
"position": "1",
|
||||
"track-count": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
releases = {'search': {}, 'get': {}, 'browse': {}}
|
||||
releases['search']['brontide matador'] = {
|
||||
"release-count": 116, "release-list": [
|
||||
{
|
||||
"ext:score": "100",
|
||||
"date": "2009-04-02",
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"name": "[Worldwide]",
|
||||
"sort-name": "[Worldwide]",
|
||||
"id": "525d4e18-3d00-31b9-a58b-a146a916de8f",
|
||||
"iso-3166-1-code-list": ["XW"]
|
||||
},
|
||||
"date": "2009-04-02"
|
||||
}
|
||||
],
|
||||
"label-info-list": [
|
||||
{
|
||||
"label": {
|
||||
"name": "Holy Roar",
|
||||
"id": "6e940f35-961d-4ac3-bc2a-569fc211c2e3"
|
||||
}
|
||||
}
|
||||
],
|
||||
"medium-track-count": 3,
|
||||
"packaging": "None",
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"name": "Brontide",
|
||||
"sort-name": "Brontide",
|
||||
"id": "2179fbd2-3c88-4b94-a778-eb3daf1e81a1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"artist-credit-phrase": "Brontide",
|
||||
"country": "XW",
|
||||
"title": "Brontide EP",
|
||||
"status": "Official",
|
||||
"barcode": "",
|
||||
"id": "59fbd4d1-6121-40e3-9b76-079694fe9702",
|
||||
"release-group": {
|
||||
"type": "EP",
|
||||
"secondary-type-list": ["Demo"],
|
||||
"id": "b9207129-2d03-4a68-8a53-3c46fe7d2810",
|
||||
"primary-type": "EP"
|
||||
},
|
||||
"medium-list": [
|
||||
{
|
||||
"disc-list": [],
|
||||
"format": "Digital Media",
|
||||
"disc-count": 0,
|
||||
"track-count": 3,
|
||||
"track-list": []
|
||||
}
|
||||
],
|
||||
"medium-count": 1,
|
||||
"text-representation": {
|
||||
"script": "Latn",
|
||||
"language": "eng"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
releases['browse']['Lost in the 80s'] = {
|
||||
"release-count": 3,
|
||||
"release-list": [
|
||||
{
|
||||
"quality": "normal",
|
||||
"status": "Official",
|
||||
"text-representation": {
|
||||
"script": "Latn",
|
||||
"language": "eng"
|
||||
},
|
||||
"title": "Lost in the 80s",
|
||||
"date": "2008-05-06",
|
||||
"release-event-count": 1,
|
||||
"id": "34e27fa0-aad4-4cc5-83a3-0f97089154dc",
|
||||
"barcode": "622406580223",
|
||||
"medium-count": 1,
|
||||
"release-event-list": [
|
||||
{
|
||||
"area": {
|
||||
"iso-3166-1-code-list": [
|
||||
"CA"
|
||||
],
|
||||
"id": "71bbafaa-e825-3e15-8ca9-017dcad1748b",
|
||||
"name": "Canada",
|
||||
"sort-name": "Canada"
|
||||
},
|
||||
"date": "2008-05-06"
|
||||
}
|
||||
],
|
||||
"country": "CA",
|
||||
"cover-art-archive": {
|
||||
"back": "false",
|
||||
"artwork": "false",
|
||||
"front": "false",
|
||||
"count": "0"
|
||||
},
|
||||
"medium-list": [
|
||||
{
|
||||
"position": "1",
|
||||
"track-count": 12,
|
||||
"format": "CD",
|
||||
"track-list": [
|
||||
{
|
||||
"id": "1662bdf8-31d6-3f6e-846b-fe88c087b109",
|
||||
"length": "228000",
|
||||
"recording": {
|
||||
"id": "2e0dbf37-65af-4408-8def-7b0b3cb8426b",
|
||||
"length": "228000",
|
||||
"title": "Pump Up the Jam"
|
||||
},
|
||||
"track_or_recording_length": "228000",
|
||||
"position": "1",
|
||||
"number": "1"
|
||||
},
|
||||
{
|
||||
"id": "01a8cf99-2170-3d3f-96ef-5e4ef7a015a4",
|
||||
"length": "231000",
|
||||
"recording": {
|
||||
"id": "57017e2e-625d-4e7b-a445-47cdb0224dd2",
|
||||
"length": "231000",
|
||||
"title": "You Give Love a Bad Name"
|
||||
},
|
||||
"track_or_recording_length": "231000",
|
||||
"position": "2",
|
||||
"number": "2"
|
||||
},
|
||||
{
|
||||
"id": "375a7ce7-5a41-3fbf-9809-96d491401034",
|
||||
"length": "189000",
|
||||
"recording": {
|
||||
"id": "a948672b-b42d-44a5-89b0-7e9ab6a7e11d",
|
||||
"length": "189000",
|
||||
"title": "You Shook Me All Night Long"
|
||||
},
|
||||
"track_or_recording_length": "189000",
|
||||
"position": "3",
|
||||
"number": "3"
|
||||
},
|
||||
{
|
||||
"id": "ed7d823e-76da-31be-82a8-770288e27d32",
|
||||
"length": "253000",
|
||||
"recording": {
|
||||
"id": "6e097e31-f37b-4fae-8ad0-ada57f3091a7",
|
||||
"length": "253000",
|
||||
"title": "Incognito"
|
||||
},
|
||||
"track_or_recording_length": "253000",
|
||||
"position": "4",
|
||||
"number": "4"
|
||||
},
|
||||
{
|
||||
"id": "76ac8c77-6a99-34d9-ae4d-be8f056d50e0",
|
||||
"length": "221000",
|
||||
"recording": {
|
||||
"id": "faa922e6-e834-44ee-8125-79e640a690e3",
|
||||
"length": "221000",
|
||||
"title": "Touch Me"
|
||||
},
|
||||
"track_or_recording_length": "221000",
|
||||
"position": "5",
|
||||
"number": "5"
|
||||
},
|
||||
{
|
||||
"id": "d0a87409-2be6-3ab7-8526-4313e7134be1",
|
||||
"length": "228000",
|
||||
"recording": {
|
||||
"id": "02da8148-60d8-4c79-ab31-8d90d233d711",
|
||||
"length": "228000",
|
||||
"title": "Part-Time Lover"
|
||||
},
|
||||
"track_or_recording_length": "228000",
|
||||
"position": "6",
|
||||
"number": "6"
|
||||
},
|
||||
{
|
||||
"id": "02c5384b-5ca9-38e9-8b7c-c08dce608deb",
|
||||
"length": "248000",
|
||||
"recording": {
|
||||
"id": "40085704-d6ab-44f6-a4d8-b27c9ca25b31",
|
||||
"length": "248000",
|
||||
"title": "Fresh"
|
||||
},
|
||||
"track_or_recording_length": "248000",
|
||||
"position": "7",
|
||||
"number": "7"
|
||||
},
|
||||
{
|
||||
"id": "ab389542-53d5-346a-b168-1d915ecf0ef6",
|
||||
"length": "257000",
|
||||
"recording": {
|
||||
"id": "77edd338-eeaf-4157-9e2a-5cc3bcee8abd",
|
||||
"length": "257000",
|
||||
"title": "Billie Jean"
|
||||
},
|
||||
"track_or_recording_length": "257000",
|
||||
"position": "8",
|
||||
"number": "8"
|
||||
},
|
||||
{
|
||||
"id": "6d9e722b-7408-350e-bb7c-2de1e329ae84",
|
||||
"length": "293000",
|
||||
"recording": {
|
||||
"id": "040aaffa-7206-40ff-9930-469413fe2420",
|
||||
"length": "293000",
|
||||
"title": "Careless Whisper"
|
||||
},
|
||||
"track_or_recording_length": "293000",
|
||||
"position": "9",
|
||||
"number": "9"
|
||||
},
|
||||
{
|
||||
"id": "63b4e67c-7536-3cd0-8c47-0310c1e40866",
|
||||
"length": "211000",
|
||||
"recording": {
|
||||
"id": "054942f0-4c0f-4e92-a606-d590976b1cff",
|
||||
"length": "211000",
|
||||
"title": "Tainted Love"
|
||||
},
|
||||
"track_or_recording_length": "211000",
|
||||
"position": "10",
|
||||
"number": "10"
|
||||
},
|
||||
{
|
||||
"id": "a07f4ca3-dbf0-3337-a247-afcd0509334a",
|
||||
"length": "245000",
|
||||
"recording": {
|
||||
"id": "8023b5ad-649a-4c67-b7a2-e12358606f6e",
|
||||
"length": "245000",
|
||||
"title": "Straight Up"
|
||||
},
|
||||
"track_or_recording_length": "245000",
|
||||
"position": "11",
|
||||
"number": "11"
|
||||
},
|
||||
{
|
||||
"id": "73d47f16-b18d-36ff-b0bb-1fa1fd32ebf7",
|
||||
"length": "322000",
|
||||
"recording": {
|
||||
"id": "95a8c8a1-fcb6-4cbb-a853-be86d816b357",
|
||||
"length": "322000",
|
||||
"title": "Black Velvet"
|
||||
},
|
||||
"track_or_recording_length": "322000",
|
||||
"position": "12",
|
||||
"number": "12"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"asin": "B0017M8YTO"
|
||||
},
|
||||
]
|
||||
}
|
|
@ -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')))
|
|
@ -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)
|
13
api/funkwhale_api/playlists/factories.py
Normal file
13
api/funkwhale_api/playlists/factories.py
Normal file
|
@ -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'
|
|
@ -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])
|
|
@ -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])
|
|
@ -1,162 +0,0 @@
|
|||
|
||||
|
||||
search = {}
|
||||
|
||||
|
||||
search['8 bit adventure'] = {
|
||||
"pageInfo": {
|
||||
"totalResults": 1000000,
|
||||
"resultsPerPage": 25
|
||||
},
|
||||
"nextPageToken": "CBkQAA",
|
||||
"etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/1L34zetsKWv-raAFiz0MuT0SsfQ\"",
|
||||
"items": [
|
||||
{
|
||||
"id": {
|
||||
"videoId": "0HxZn6CzOIo",
|
||||
"kind": "youtube#video"
|
||||
},
|
||||
"etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/GxK-wHBWUYfrJsd1dijBPTufrVE\"",
|
||||
"snippet": {
|
||||
"liveBroadcastContent": "none",
|
||||
"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",
|
||||
"thumbnails": {
|
||||
"medium": {
|
||||
"url": "https://i.ytimg.com/vi/0HxZn6CzOIo/mqdefault.jpg",
|
||||
"height": 180,
|
||||
"width": 320
|
||||
},
|
||||
"high": {
|
||||
"url": "https://i.ytimg.com/vi/0HxZn6CzOIo/hqdefault.jpg",
|
||||
"height": 360,
|
||||
"width": 480
|
||||
},
|
||||
"default": {
|
||||
"url": "https://i.ytimg.com/vi/0HxZn6CzOIo/default.jpg",
|
||||
"height": 90,
|
||||
"width": 120
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "youtube#searchResult"
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"videoId": "n4A_F5SXmgo",
|
||||
"kind": "youtube#video"
|
||||
},
|
||||
"etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/aRVESw24jlgiErDgJKxNrazKRDc\"",
|
||||
"snippet": {
|
||||
"liveBroadcastContent": "none",
|
||||
"description": "Free Download: http://bit.ly/1fZ1pMJ I don't post 8 bit'ish music much but damn I must admit this is goood! Enjoy \u2665 \u25bbSpikedGrin: ...",
|
||||
"channelId": "UCMOgdURr7d8pOVlc-alkfRg",
|
||||
"title": "\u3010Electro\u3011AdhesiveWombat - 8 Bit Adventure (SpikedGrin Remix) [Free Download]",
|
||||
"channelTitle": "xKito Music",
|
||||
"publishedAt": "2013-10-27T13:16:48.000Z",
|
||||
"thumbnails": {
|
||||
"medium": {
|
||||
"url": "https://i.ytimg.com/vi/n4A_F5SXmgo/mqdefault.jpg",
|
||||
"height": 180,
|
||||
"width": 320
|
||||
},
|
||||
"high": {
|
||||
"url": "https://i.ytimg.com/vi/n4A_F5SXmgo/hqdefault.jpg",
|
||||
"height": 360,
|
||||
"width": 480
|
||||
},
|
||||
"default": {
|
||||
"url": "https://i.ytimg.com/vi/n4A_F5SXmgo/default.jpg",
|
||||
"height": 90,
|
||||
"width": 120
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "youtube#searchResult"
|
||||
},
|
||||
],
|
||||
"regionCode": "FR",
|
||||
"kind": "youtube#searchListResponse"
|
||||
}
|
||||
|
||||
search['system of a down toxicity'] = {
|
||||
"items": [
|
||||
{
|
||||
"id": {
|
||||
"kind": "youtube#video",
|
||||
"videoId": "BorYwGi2SJc"
|
||||
},
|
||||
"kind": "youtube#searchResult",
|
||||
"snippet": {
|
||||
"title": "System of a Down: Toxicity",
|
||||
"channelTitle": "Vedres Csaba",
|
||||
"channelId": "UCBXeuQORNwPv4m68fgGMtPQ",
|
||||
"thumbnails": {
|
||||
"default": {
|
||||
"height": 90,
|
||||
"width": 120,
|
||||
"url": "https://i.ytimg.com/vi/BorYwGi2SJc/default.jpg"
|
||||
},
|
||||
"high": {
|
||||
"height": 360,
|
||||
"width": 480,
|
||||
"url": "https://i.ytimg.com/vi/BorYwGi2SJc/hqdefault.jpg"
|
||||
},
|
||||
"medium": {
|
||||
"height": 180,
|
||||
"width": 320,
|
||||
"url": "https://i.ytimg.com/vi/BorYwGi2SJc/mqdefault.jpg"
|
||||
}
|
||||
},
|
||||
"publishedAt": "2007-12-17T12:39:54.000Z",
|
||||
"description": "http://www.vedrescsaba.uw.hu The System of a Down song Toxicity arranged for a classical piano quintet, played by Vedres Csaba and the Kairosz quartet.",
|
||||
"liveBroadcastContent": "none"
|
||||
},
|
||||
"etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/UwR8H6P6kbijNZmBNkYd2jAzDnI\""
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"kind": "youtube#video",
|
||||
"videoId": "ENBv2i88g6Y"
|
||||
},
|
||||
"kind": "youtube#searchResult",
|
||||
"snippet": {
|
||||
"title": "System Of A Down - Question!",
|
||||
"channelTitle": "systemofadownVEVO",
|
||||
"channelId": "UCvtZDkeFxMkRTNqfqXtxxkw",
|
||||
"thumbnails": {
|
||||
"default": {
|
||||
"height": 90,
|
||||
"width": 120,
|
||||
"url": "https://i.ytimg.com/vi/ENBv2i88g6Y/default.jpg"
|
||||
},
|
||||
"high": {
|
||||
"height": 360,
|
||||
"width": 480,
|
||||
"url": "https://i.ytimg.com/vi/ENBv2i88g6Y/hqdefault.jpg"
|
||||
},
|
||||
"medium": {
|
||||
"height": 180,
|
||||
"width": 320,
|
||||
"url": "https://i.ytimg.com/vi/ENBv2i88g6Y/mqdefault.jpg"
|
||||
}
|
||||
},
|
||||
"publishedAt": "2009-10-03T04:49:03.000Z",
|
||||
"description": "System of a Down's official music video for 'Question!'. Click to listen to System of a Down on Spotify: http://smarturl.it/SystemSpotify?IQid=SystemQu As featured ...",
|
||||
"liveBroadcastContent": "none"
|
||||
},
|
||||
"etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/dB-M0N9mB4xE-k4yAF_4d8aU0I4\""
|
||||
},
|
||||
],
|
||||
"etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/yhLQgSpeObNnybd5JqSzlGiJ8Ew\"",
|
||||
"nextPageToken": "CBkQAA",
|
||||
"pageInfo": {
|
||||
"resultsPerPage": 25,
|
||||
"totalResults": 26825
|
||||
},
|
||||
"kind": "youtube#searchListResponse",
|
||||
"regionCode": "FR"
|
||||
}
|
|
@ -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])
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -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()
|
||||
)
|
|
@ -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)
|
|
@ -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)
|
Loading…
Add table
Add a link
Reference in a new issue