def test_playlist_includes_songs_from_other_artists_if_top_artist_playlist_is_less_than_limit( self): top_artists = ['Madlib', 'MF DOOM', 'Surf Curse'] song_params = { 'energy': .5, 'valence': .75, 'danceability': .65, } top_artist_song = MoodyUtil.create_song(artist=top_artists[0], **song_params) # Create songs from other artists for _ in range(10): artist = ''.join( [random.choice(string.ascii_letters) for _ in range(10)]) MoodyUtil.create_song(artist=artist, **song_params) limit = 5 playlist = generate_browse_playlist(song_params['energy'], song_params['valence'], song_params['danceability'], jitter=0, top_artists=top_artists, limit=limit) self.assertEqual(len(playlist), limit) self.assertIn(top_artist_song, playlist)
def setUpTestData(cls): cls.song_1 = MoodyUtil.create_song(energy=.5, valence=.75, danceability=.5) cls.song_2 = MoodyUtil.create_song(energy=.65, valence=.45, danceability=.75)
def test_top_artists_passed_returns_songs_by_top_artists(self): top_artists = ['Madlib', 'MF DOOM', 'Surf Curse'] song_params = { 'energy': .5, 'valence': .75, 'danceability': .65, } for artist in top_artists: MoodyUtil.create_song(artist=artist, **song_params) MoodyUtil.create_song(artist='Bum', **song_params) expected_playlist = list(Song.objects.filter(artist__in=top_artists)) playlist = generate_browse_playlist(song_params['energy'], song_params['valence'], song_params['danceability'], jitter=0, top_artists=top_artists) # Sort playlists for comparison as the playlist is shuffled playlist = list(playlist) expected_playlist.sort(key=lambda song: song.code) playlist.sort(key=lambda song: song.code) self.assertListEqual(expected_playlist, playlist)
def test_retrieve_cached_playlist_returns_cached_playlist( self, mock_cache): MoodyUtil.create_song() playlist = Song.objects.all() mock_cache.get.return_value = playlist returned_playlist = self.manager.retrieve_cached_browse_playlist() self.assertEqual(playlist, returned_playlist)
def test_happy_path(self): song = MoodyUtil.create_song(valence=.5, energy=.75) outlier_song = MoodyUtil.create_song(valence=.25, energy=.30) playlist = generate_browse_playlist(song.energy, song.valence, song.danceability) self.assertIn(song, playlist) self.assertNotIn(outlier_song, playlist)
def test_playlist_respects_limit(self): for _ in range(10): MoodyUtil.create_song() params = {'emotion': Emotion.HAPPY, 'jitter': 0, 'limit': 5} resp = self.client.get(self.url, data=params) resp_data = resp.json()['results'] self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp_data), params['limit'])
def test_method_omits_empty_genre(self): song_with_genre = MoodyUtil.create_song(genre='hiphop') MoodyUtil.create_song(genre='') expected_choices = [ default_option[0], (song_with_genre.genre, song_with_genre.genre.capitalize()), ] choices = get_genre_choices() self.assertEqual(choices, expected_choices)
def test_method_returns_all_song_genres(self): hiphop_song = MoodyUtil.create_song(genre='hiphop') rock_song = MoodyUtil.create_song(genre='rock') expected_choices = [ default_option[0], (hiphop_song.genre, hiphop_song.genre.capitalize()), (rock_song.genre, rock_song.genre.capitalize()) ] choices = get_genre_choices() self.assertEqual(choices, expected_choices)
def test_cache_browse_playlist_calls_cache_with_expected_arguments( self, mock_cache): MoodyUtil.create_song() data = { 'emotion': 'HPY', 'context': 'WORK', 'description': '', 'playlist': Song.objects.all() } cache_key = 'browse:cached-playlist:{}'.format(self.user.username) self.manager.cache_browse_playlist(**data) mock_cache.set.assert_called_once_with( cache_key, data, settings.BROWSE_PLAYLIST_CACHE_TIMEOUT)
def test_limit_on_playlist(self): energy = .5 valence = .75 danceability = .65 for _ in range(10): MoodyUtil.create_song(energy=energy, valence=valence, danceability=danceability) playlist = generate_browse_playlist(energy, valence, danceability, limit=5) self.assertEqual(len(playlist), 5)
def test_filter_on_genre(self): MoodyUtil.create_song() expected_song = MoodyUtil.create_song(genre='super-dope') params = { 'emotion': Emotion.HAPPY, 'jitter': 0, 'genre': expected_song.genre } resp = self.client.get(self.url, data=params) resp_data = resp.json()['results'] resp_song = resp_data[0] self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(resp_song['code'], expected_song.code)
def test_playlist_for_context_is_generated_with_upvoted_song_attributes_for_context( self, mock_generate_playlist): context = 'WORK' emotion = Emotion.objects.get(name=Emotion.HAPPY) song = MoodyUtil.create_song(energy=.25, valence=.50, danceability=.75) song2 = MoodyUtil.create_song(energy=.75, valence=.50, danceability=.25) song3 = MoodyUtil.create_song(energy=.50, valence=.75, danceability=.25) MoodyUtil.create_user_song_vote(self.user, song, emotion, True, context=context) MoodyUtil.create_user_song_vote(self.user, song2, emotion, True, context=context) MoodyUtil.create_user_song_vote( self.user, song3, emotion, True) # Attributes should not be factored in params = {'emotion': emotion.name, 'jitter': 0, 'context': context} self.client.get(self.url, data=params) votes = UserSongVote.objects.filter(user=self.user, emotion=emotion, context=context, vote=True) attributes_for_votes = average(votes, 'song__valence', 'song__energy', 'song__danceability') expected_valence = attributes_for_votes['song__valence__avg'] expected_energy = attributes_for_votes['song__energy__avg'] expected_danceability = attributes_for_votes['song__danceability__avg'] call_args = mock_generate_playlist.mock_calls[0][1] called_energy = call_args[0] called_valence = call_args[1] called_danceability = call_args[2] self.assertEqual(called_valence, expected_valence) self.assertEqual(called_energy, expected_energy) self.assertEqual(called_danceability, expected_danceability)
def test_first_and_last_page_links_are_populated_on_paginated_response_with_zeros_in_next_page( self): votes = [] for _ in range(100): song = MoodyUtil.create_song() votes.append( UserSongVote(user=self.user, emotion=self.emotion, song=song, vote=True)) # Use bulk_create method to skip updating UserEmotion attributes UserSongVote.objects.bulk_create(votes) data = {'emotion': self.emotion.name, 'page': 9} resp = self.client.get(self.url, data=data) resp_data = resp.json() self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(resp_data['first_page'], 'http://testserver/tunes/playlist/?emotion=HPY') self.assertEqual( resp_data['last_page'], 'http://testserver/tunes/playlist/?emotion=HPY&page=last')
def test_cached_playlist_exists_is_true_in_context(self, mock_cache_retrieve): song = MoodyUtil.create_song() mock_cache_retrieve.return_value = [song] resp = self.client.get(self.url) self.assertTrue(resp.context['cached_playlist_exists'])
def test_first_and_last_page_links_contain_genre_when_provided(self): votes = [] for _ in range(30): song = MoodyUtil.create_song(genre='hiphop') votes.append( UserSongVote(user=self.user, emotion=self.emotion, song=song, vote=True)) # Use bulk_create method to skip updating UserEmotion attributes UserSongVote.objects.bulk_create(votes) data = {'emotion': self.emotion.name, 'page': 2, 'genre': 'hiphop'} resp = self.client.get(self.url, data=data) resp_data = resp.json() self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual( resp_data['first_page'], 'http://testserver/tunes/playlist/?emotion=HPY&genre=hiphop') self.assertEqual( resp_data['last_page'], 'http://testserver/tunes/playlist/?emotion=HPY&genre=hiphop&page=last' )
def test_upvoting_on_song_updates_user_emotion_attributes(self): user_emotion = self.user.useremotion_set.get( emotion__name=Emotion.HAPPY) new_song = MoodyUtil.create_song(energy=.75, valence=.65) data = { 'emotion': Emotion.HAPPY, 'song_code': self.song.code, 'vote': True } self.client.post(self.url, data=data, format='json') data = { 'emotion': Emotion.HAPPY, 'song_code': new_song.code, 'vote': True } self.client.post(self.url, data=data, format='json') votes = UserSongVote.objects.filter(user=self.user, vote=True) expected_attributes = average(votes, 'song__valence', 'song__energy', 'song__danceability') expected_valence = expected_attributes['song__valence__avg'] expected_energy = expected_attributes['song__energy__avg'] expected_danceability = expected_attributes['song__danceability__avg'] user_emotion.refresh_from_db() self.assertEqual(user_emotion.energy, expected_energy) self.assertEqual(user_emotion.valence, expected_valence) self.assertEqual(user_emotion.danceability, expected_danceability)
def test_filter_playlist_by_genre(self): new_song = MoodyUtil.create_song(genre='super-dope') MoodyUtil.create_user_song_vote(user=self.user, song=self.song, emotion=self.emotion, vote=True) MoodyUtil.create_user_song_vote(user=self.user, song=new_song, emotion=self.emotion, vote=True) data = {'emotion': self.emotion.name, 'genre': new_song.genre} resp = self.client.get(self.url, data=data) resp_data = resp.json() queryset = UserSongVote.objects.filter(user=self.user, emotion=self.emotion, vote=True, song__genre=new_song.genre) votes_for_emotion_data = average(queryset, 'song__valence', 'song__energy', 'song__danceability') valence = votes_for_emotion_data['song__valence__avg'] * 100 energy = votes_for_emotion_data['song__energy__avg'] * 100 danceability = votes_for_emotion_data['song__danceability__avg'] * 100 self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp_data['results']), 1) self.assertEqual(resp_data['results'][0]['song']['code'], new_song.code) self.assertEqual(resp_data['valence'], valence) self.assertEqual(resp_data['energy'], energy) self.assertEqual(resp_data['danceability'], danceability)
def test_task_does_not_call_spotify_if_song_already_exists( self, mock_get_attributes, mock_get_features): song = MoodyUtil.create_song() FetchSongFromSpotifyTask().run(song.code) mock_get_attributes.assert_not_called() mock_get_features.assert_not_called()
def test_playlist_excludes_previously_voted_songs(self): voted_song = MoodyUtil.create_song() not_voted_song = MoodyUtil.create_song() UserSongVote.objects.create( user=self.user, song=voted_song, emotion=Emotion.objects.get(name=Emotion.HAPPY), vote=True) params = {'emotion': Emotion.HAPPY, 'jitter': 0} resp = self.client.get(self.url, data=params) resp_data = resp.json()['results'] self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp_data), 1) self.assertEqual(resp_data[0]['code'], not_voted_song.code)
def test_happy_path(self): song = MoodyUtil.create_song() params = {'emotion': Emotion.HAPPY, 'jitter': 0} resp = self.client.get(self.url, data=params) resp_data = resp.json()['results'] resp_song = resp_data[0] self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(resp_song['code'], song.code)
def setUpTestData(cls): cls.user = MoodyUtil.create_user() cls.auth = MoodyUtil.create_spotify_auth(cls.user) cls.playlist_name = 'new_playlist' cls.playlist_id = 'spotify:playlist:id' cls.songs = [] for i in range(30): cls.songs.append(MoodyUtil.create_song().code)
def test_artist_passed_only_returns_songs_from_artist(self): artist = 'TTK' song_params = { 'energy': .5, 'valence': .75, 'danceability': .65, } song_from_artist = MoodyUtil.create_song(artist=artist, **song_params) song_from_other_artist = MoodyUtil.create_song(artist='Bum', **song_params) playlist = generate_browse_playlist(song_params['energy'], song_params['valence'], song_params['danceability'], jitter=0, artist=artist) self.assertIn(song_from_artist, playlist) self.assertNotIn(song_from_other_artist, playlist)
def test_playlist_uses_default_jitter_if_not_provided( self, mock_generate_playlist): song = MoodyUtil.create_song() mock_generate_playlist.return_value = [song] params = {'emotion': Emotion.HAPPY} self.client.get(self.url, data=params) call_kwargs = mock_generate_playlist.mock_calls[0][2] called_jitter = call_kwargs['jitter'] self.assertEqual(called_jitter, BrowseView.default_jitter)
def test_filter_does_not_remove_different_songs(self): other_song = MoodyUtil.create_song() MoodyUtil.create_user_song_vote(self.user, self.song, self.emotion, True) MoodyUtil.create_user_song_vote(self.user, other_song, self.emotion, True) user_votes = UserSongVote.objects.filter(user=self.user, emotion=self.emotion) filtered_votes = filter_duplicate_votes_on_song_from_playlist( user_votes) self.assertEqual(filtered_votes.count(), 2)
def test_filter_by_genre(self): genre = 'hiphop' other_song = MoodyUtil.create_song(genre=genre) MoodyUtil.create_user_song_vote(self.user, self.song, self.emotion, True) MoodyUtil.create_user_song_vote(self.user, other_song, self.emotion, True) songs = ExportPlaylistHelper.get_export_playlist_for_user( self.user, self.emotion.name, genre=other_song.genre) self.assertIn(other_song.code, songs) self.assertNotIn(self.song.code, songs)
def test_post_request_with_invalid_playlist_name_displays_error(self): song = MoodyUtil.create_song() MoodyUtil.create_user_song_vote(self.user, song, self.emotion, True) data = { 'playlist_name': 'test|timeout /T 15', 'emotion': self.emotion.name, } resp = self.client.post(self.url, data) messages = get_messages_from_response(resp) last_message = messages[-1] msg = 'Please submit a valid request' self.assertEqual(last_message, msg)
def test_post_request_happy_path(self, mock_task_call): song = MoodyUtil.create_song() MoodyUtil.create_user_song_vote(self.user, song, self.emotion, True) data = { 'playlist_name': self.test_playlist_name, 'emotion': self.emotion.name } resp = self.client.post(self.url, data) mock_task_call.assert_called_once_with( self.spotify_auth.pk, self.test_playlist_name, [song.code], None, trace_id=resp.wsgi_request.trace_id)
def test_endpoint_only_returns_contexts_for_specified_song(self): other_song = MoodyUtil.create_song() MoodyUtil.create_user_song_vote(self.user, self.song, self.emotion, True, 'PARTY') MoodyUtil.create_user_song_vote(self.user, other_song, self.emotion, True, 'WORK') data = {'emotion': self.emotion.name, 'song_code': self.song.code} resp = self.client.get(self.url, data=data) resp_data = resp.json() expected_contexts = ['PARTY'] self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(resp_data['contexts'], expected_contexts)
def test_browse_request_caches_playlist(self, mock_cache, mock_generate_playlist): song = MoodyUtil.create_song() song_queryset = Song.objects.filter(code=song.code) mock_generate_playlist.return_value = song_queryset params = { 'emotion': Emotion.HAPPY, 'jitter': 0, 'context': 'WORK', 'description': 'Working on stuff' } self.client.get(self.url, data=params) mock_cache.assert_called_once_with(song_queryset, Emotion.HAPPY, 'WORK', 'Working on stuff')
def test_filter_by_artist(self): expected_song = MoodyUtil.create_song(artist='Cool Artist') MoodyUtil.create_user_song_vote(self.user, self.song, self.emotion, True) MoodyUtil.create_user_song_vote(self.user, expected_song, self.emotion, True) data = {'emotion': self.emotion.name, 'artist': expected_song.artist} resp = self.client.get(self.url, data=data) resp_data = resp.json() self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp_data['results']), 1) self.assertEqual(resp_data['results'][0]['song']['code'], expected_song.code)