Skip to content

Commit

Permalink
Fixing unittests for player queue view
Browse files Browse the repository at this point in the history
  • Loading branch information
krak3n committed Apr 9, 2015
1 parent ff78814 commit e751384
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 113 deletions.
7 changes: 6 additions & 1 deletion fm/serializers/types/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ def marshal_value(self, value):
return self.track

def validate(self, value):
try:
id = value.split(':')[-1:][0]
except IndexError:
raise ValidationError('Invalid Spotify URI: {0}'.format(value))

endpoint = 'https://api.spotify.com/v1/tracks/{0}'.format(id)

try:
Expand All @@ -21,7 +26,7 @@ def validate(self, value):
raise ValidationError('Unable to get track data from Spotify')

if not response.status_code == 200:
raise ValidationError('Invalid Spotify URI: {0}'.format(value))
raise ValidationError('Invalid Spotify Track ID: {0}'.format(id))

try:
track = response.json()
Expand Down
59 changes: 11 additions & 48 deletions fm/views/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
from fm import http
from fm.ext import config, db, redis
from fm.logic.player import Queue, Random
from fm.models.spotify import Album, Artist, PlaylistHistory, Track
from fm.models.spotify import PlaylistHistory, Track
from fm.models.user import User
from fm.serializers.player import PlaylistSerializer, VolumeSerializer
from fm.serializers.spotify import HistorySerializer, TrackSerializer
from fm.serializers.user import UserSerializer
from fm.session import authenticated, current_user
from fm.tasks.queue import add
from kim.exceptions import MappingErrors
from sqlalchemy import desc

Expand Down Expand Up @@ -263,63 +264,25 @@ def get(self, *args, **kwargs):
total=total,
limit=limit)

# TODO: Refactor this resource, its getting a tad large
@authenticated
def post(self):
""" Allows you to add anew track to the player playlist.
"""

serializer = PlaylistSerializer()

try:
data = serializer.marshal(request.json)
track = serializer.marshal(request.json)
except MappingErrors as e:
return http.UnprocessableEntity(errors=e.message)

album = Album.query.filter(Album.spotify_uri == data['track']['album']['uri']).first()
if album is None:
album = Album()
db.session.add(album)

album.name = data['track']['album']['name']
album.images = data['track']['album']['images']
album.spotify_uri = data['track']['album']['uri']

db.session.commit()

for item in data['track']['artists']:
artist = Artist.query.filter(Artist.spotify_uri == item['uri']).first()
if artist is None:
artist = Artist()
db.session.add(artist)

artist.name = item['name']
artist.spotify_uri = item['uri']

if artist not in album.artists:
album.artists.append(artist)

db.session.commit()

track = Track.query.filter(Track.spotify_uri == data['track']['uri']).first()
if track is None:
track = Track()
db.session.add(track)

track.name = data['track']['name']
track.spotify_uri = data['track']['uri']
track.duration = data['track']['duration_ms']
track.album_id = album.id

# If a track is skipped we should decrement the play count
try:
track.play_count += 1
except TypeError as e:
track.play_count = 1

db.session.commit()
# Dispatch Celery Task
add.delay(track['track'], current_user.id)

Queue.add(track, current_user)
return http.Created(location=url_for('tracks.track', pk_or_uri=track.id))
return http.Created(location=url_for(
'tracks.track',
pk_or_uri=track['track']['uri'],
_external=True))


class RandomView(MethodView):
Expand All @@ -332,6 +295,6 @@ def post(self):
'track': TrackSerializer().serialize(track),
'user': UserSerializer().serialize(current_user)
})
Queue.add(track, current_user)
Queue.add(track.spotify_uri, current_user.id)

return http.Created(response)
91 changes: 27 additions & 64 deletions tests/views/player/test_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@
Unit tests for the ``fm.views.player.QueueView`` class.
"""

import httplib
import json
import mock
import pytest
import requests

from fm.ext import db
from fm.models.spotify import Album, Artist, Track
from fm.ext import config, db
from fm.models.user import User
from fm.serializers.spotify import TrackSerializer
from fm.serializers.user import UserSerializer
from flask import url_for
from mockredis import mock_redis_client
from tests import TRACK_DATA
from tests.factories.spotify import TrackFactory
from tests.factories.user import UserFactory
Expand Down Expand Up @@ -110,7 +112,7 @@ def setup(self):

self.requests = mock.MagicMock()
self.requests.get.return_value = mock.MagicMock(
status_code=200,
status_code=httplib.OK,
json=mock.MagicMock(return_value=TRACK_DATA))
self.requests.ConnectionError = requests.ConnectionError

Expand All @@ -120,11 +122,11 @@ def setup(self):
new_callable=mock.PropertyMock(return_value=self.requests))

patch.start()

self.addPatchCleanup(patch)

patch = mock.patch('fm.views.player.Queue')
patch.start()
patch = mock.patch('fm.logic.player.redis', mock_redis_client())
self.redis = patch.start()
self.redis.publish = mock.MagicMock()
self.addPatchCleanup(patch)

@pytest.mark.usefixtures("unauthenticated")
Expand All @@ -134,84 +136,45 @@ def must_be_authenticated(self):
'track': 'foo'
}))

assert response.status_code == 401
assert response.status_code == httplib.UNAUTHORIZED

def should_catch_connection_error(self):
self.requests.get.side_effect = requests.ConnectionError()

url = url_for('player.queue')
response = self.client.post(url, data=json.dumps({
'track': 'foo'
'track': 'spotify:track:foo'
}))

assert response.status_code == 422
assert response.status_code == httplib.UNPROCESSABLE_ENTITY
assert 'Unable to get track data from Spotify' in response.json['errors']['track']

def ensure_valid_spotify_uri(self):
self.requests.get.return_value = mock.MagicMock(status_code=404)

url = url_for('player.queue')
response = self.client.post(url, data=json.dumps({
'track': 'foo'
'track': 'spotify:track:foo'
}))

assert response.status_code == 422
assert 'Invalid Spotify URI: foo' in response.json['errors']['track']

def should_create_new_album(self):
assert Album.query.count() == 0
assert response.status_code == httplib.UNPROCESSABLE_ENTITY
assert 'Invalid Spotify Track ID: foo' in response.json['errors']['track']

def should_call_queue_add_task(self):
url = url_for('player.queue')
response = self.client.post(url, data=json.dumps({
'track': 'foo'
'track': 'spotify:track:foo'
}))

album = Album.query.first()

assert response.status_code == 201
assert album is not None
assert album.name == TRACK_DATA['album']['name']
assert album.images == TRACK_DATA['album']['images']
assert album.spotify_uri == TRACK_DATA['album']['uri']

def should_create_artist(self):
assert Artist.query.count() == 0

url = url_for('player.queue')
response = self.client.post(url, data=json.dumps({
'track': 'foo'
queue = self.redis.get(config.PLAYLIST_REDIS_KEY)
user = User.query.one()

assert response.status_code == httplib.CREATED
assert len(queue) == 1
assert json.loads(queue[0])['user'] == user.id
assert json.loads(queue[0])['uri'] == TRACK_DATA['uri']
assert self.redis.publish.caled_once_with(json.dumps({
'event': 'add',
'uri': TRACK_DATA['uri'],
'user': user.id
}))

artist = Artist.query.first()

assert response.status_code == 201
assert artist is not None
assert artist.name == TRACK_DATA['artists'][0]['name']
assert artist.spotify_uri == TRACK_DATA['artists'][0]['uri']

def ensure_new_track_play_count_is_one(self):
url = url_for('player.queue')
response = self.client.post(url, data=json.dumps({
'track': 'foo'
}))

track = Track.query.first()

assert response.status_code == 201
assert track.play_count == 1

def should_increment_existing_track_play_count(self):
t = TrackFactory(spotify_uri=TRACK_DATA['uri'], play_count=5)

db.session.add(t)
db.session.commit()

url = url_for('player.queue')
response = self.client.post(url, data=json.dumps({
'track': t.spotify_uri
}))

track = Track.query.first()

assert response.status_code == 201
assert track.play_count == 6

0 comments on commit e751384

Please sign in to comment.