Skip to content
Snippets Groups Projects
Verified Commit 099cdfa9 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Fixed #54: Now use pytest everywhere \o/

parent a7758395
No related branches found
No related tags found
No related merge requests found
Showing
with 55 additions and 486 deletions
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])
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])
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)
import factory import factory
from funkwhale_api.factories import registry
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
@registry.register
class UserFactory(factory.django.DjangoModelFactory): class UserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: 'user-{0}'.format(n)) username = factory.Sequence(lambda n: 'user-{0}'.format(n))
email = factory.Sequence(lambda n: 'user-{0}@example.com'.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: class Meta:
model = 'users.User' model = 'users.User'
...@@ -28,3 +30,9 @@ class UserFactory(factory.django.DjangoModelFactory): ...@@ -28,3 +30,9 @@ class UserFactory(factory.django.DjangoModelFactory):
] ]
# A list of permissions were passed in, use them # A list of permissions were passed in, use them
self.user_permissions.add(*perms) self.user_permissions.add(*perms)
@registry.register(name='users.SuperUser')
class SuperUserFactory(UserFactory):
is_staff = True
is_superuser = True
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)
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()
)
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)
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)
...@@ -5,7 +5,6 @@ django_coverage_plugin>=1.5,<1.6 ...@@ -5,7 +5,6 @@ django_coverage_plugin>=1.5,<1.6
Sphinx>=1.6,<1.7 Sphinx>=1.6,<1.7
django-extensions>=1.9,<1.10 django-extensions>=1.9,<1.10
Werkzeug>=0.13,<0.14 Werkzeug>=0.13,<0.14
django-test-plus>=1.0.20
factory_boy>=2.8.1 factory_boy>=2.8.1
# django-debug-toolbar that works with Django 1.5+ # django-debug-toolbar that works with Django 1.5+
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
flake8 flake8
pytest pytest
pytest-django # pytest-django until a new release containing django_assert_num_queries
# is deployed to pypi
git+https://github.com/pytest-dev/pytest-django.git@d3d9bb3ef6f0377cb5356eb368992a0834692378
pytest-mock pytest-mock
pytest-sugar pytest-sugar
pytest-xdist pytest-xdist
import tempfile
import shutil
import pytest
@pytest.fixture(scope="session", autouse=True)
def factories_autodiscover():
from django.apps import apps
from funkwhale_api import factories
app_names = [app.name for app in apps.app_configs.values()]
factories.registry.autodiscover(app_names)
@pytest.fixture
def factories(db):
from funkwhale_api import factories
yield factories.registry
@pytest.fixture
def tmpdir():
d = tempfile.mkdtemp()
yield d
shutil.rmtree(d)
@pytest.fixture
def logged_in_client(db, factories, client):
user = factories['users.User']()
assert client.login(username=user.username, password='test')
setattr(client, 'user', user)
yield client
delattr(client, 'user')
@pytest.fixture
def superuser_client(db, factories, client):
user = factories['users.SuperUser']()
assert client.login(username=user.username, password='test')
setattr(client, 'user', user)
yield client
delattr(client, 'user')
File moved
File moved
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment