示例#1
0
    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)
示例#2
0
 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)
示例#3
0
    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)
示例#4
0
    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)
示例#5
0
    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)
示例#6
0
    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'])
示例#7
0
    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)
示例#8
0
    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)
示例#9
0
    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)
示例#10
0
    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)
示例#11
0
    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)
示例#12
0
    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)
示例#13
0
    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')
示例#14
0
    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'])
示例#15
0
    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'
        )
示例#16
0
    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)
示例#17
0
    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)
示例#18
0
    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()
示例#19
0
    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)
示例#20
0
    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)
示例#21
0
    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)
示例#22
0
    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)
示例#23
0
    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)
示例#24
0
    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)
示例#25
0
    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)
示例#26
0
    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)
示例#27
0
    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)
示例#28
0
    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)
示例#29
0
    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')
示例#30
0
    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)