2017-11-08 22:21:52 +00:00
|
|
|
#!/usr/bin/env python
|
2018-03-04 20:49:56 +00:00
|
|
|
# coding: utf-8
|
2017-11-08 22:21:52 +00:00
|
|
|
#
|
|
|
|
# This file is part of Supysonic.
|
|
|
|
# Supysonic is a Python implementation of the Subsonic server API.
|
|
|
|
#
|
2018-01-11 22:08:53 +00:00
|
|
|
# Copyright (C) 2017-2018 Alban 'spl0k' Féron
|
2017-11-08 22:21:52 +00:00
|
|
|
#
|
|
|
|
# Distributed under terms of the GNU AGPLv3 license.
|
|
|
|
|
|
|
|
import uuid
|
|
|
|
|
2018-08-11 14:16:34 +00:00
|
|
|
from pony.orm import db_session
|
|
|
|
|
|
|
|
from supysonic.db import Folder, Artist, Album, Track, Playlist, User
|
2017-11-08 22:21:52 +00:00
|
|
|
|
|
|
|
from .apitestbase import ApiTestBase
|
|
|
|
|
|
|
|
class PlaylistTestCase(ApiTestBase):
|
|
|
|
def setUp(self):
|
|
|
|
super(PlaylistTestCase, self).setUp()
|
|
|
|
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
root = Folder(root = True, name = 'Root folder', path = 'tests/assets')
|
|
|
|
artist = Artist(name = 'Artist')
|
|
|
|
album = Album(name = 'Album', artist = artist)
|
|
|
|
|
|
|
|
songs = {}
|
|
|
|
for num, song in enumerate([ 'One', 'Two', 'Three', 'Four' ]):
|
|
|
|
track = Track(
|
|
|
|
disc = 1,
|
|
|
|
number = num,
|
|
|
|
title = song,
|
|
|
|
duration = 2,
|
|
|
|
album = album,
|
|
|
|
artist = artist,
|
|
|
|
bitrate = 320,
|
|
|
|
path = 'tests/assets/' + song,
|
|
|
|
content_type = 'audio/mpeg',
|
|
|
|
last_modification = 0,
|
|
|
|
root_folder = root,
|
|
|
|
folder = root
|
|
|
|
)
|
|
|
|
songs[song] = track
|
|
|
|
|
|
|
|
users = { u.name: u for u in User.select() }
|
|
|
|
|
|
|
|
playlist = Playlist(user = users['alice'], name = "Alice's")
|
|
|
|
playlist.add(songs['One'])
|
|
|
|
playlist.add(songs['Three'])
|
|
|
|
|
|
|
|
playlist = Playlist(user = users['alice'], public = True, name = "Alice's public")
|
|
|
|
playlist.add(songs['One'])
|
|
|
|
playlist.add(songs['Two'])
|
|
|
|
|
|
|
|
playlist = Playlist(user = users['bob'], name = "Bob's")
|
|
|
|
playlist.add(songs['Two'])
|
|
|
|
playlist.add(songs['Four'])
|
2017-11-08 22:21:52 +00:00
|
|
|
|
|
|
|
def test_get_playlists(self):
|
|
|
|
# get own playlists
|
|
|
|
rv, child = self._make_request('getPlaylists', tag = 'playlists')
|
|
|
|
self.assertEqual(len(child), 2)
|
|
|
|
self.assertEqual(child[0].get('owner'), 'alice')
|
|
|
|
self.assertEqual(child[1].get('owner'), 'alice')
|
|
|
|
|
|
|
|
# get own and public
|
|
|
|
rv, child = self._make_request('getPlaylists', { 'u': 'bob', 'p': 'B0b' }, tag = 'playlists')
|
|
|
|
self.assertEqual(len(child), 2)
|
|
|
|
self.assertTrue(child[0].get('owner') == 'alice' or child[1].get('owner') == 'alice')
|
|
|
|
self.assertTrue(child[0].get('owner') == 'bob' or child[1].get('owner') == 'bob')
|
|
|
|
self.assertIsNotNone(self._find(child, "./playlist[@owner='alice'][@public='true']"))
|
|
|
|
|
|
|
|
# get other
|
|
|
|
rv, child = self._make_request('getPlaylists', { 'username': 'bob' }, tag = 'playlists')
|
|
|
|
self.assertEqual(len(child), 1)
|
|
|
|
self.assertEqual(child[0].get('owner'), 'bob')
|
|
|
|
|
|
|
|
# get other when not admin
|
|
|
|
self._make_request('getPlaylists', { 'u': 'bob', 'p': 'B0b', 'username': 'alice' }, error = 50)
|
|
|
|
|
|
|
|
# get from unknown user
|
|
|
|
self._make_request('getPlaylists', { 'username': 'johndoe' }, error = 70)
|
|
|
|
|
|
|
|
def test_get_playlist(self):
|
|
|
|
# missing param
|
|
|
|
self._make_request('getPlaylist', error = 10)
|
|
|
|
|
|
|
|
# invalid id
|
|
|
|
self._make_request('getPlaylist', { 'id': 1234 }, error = 0)
|
|
|
|
|
|
|
|
# unknown
|
|
|
|
self._make_request('getPlaylist', { 'id': str(uuid.uuid4()) }, error = 70)
|
|
|
|
|
|
|
|
# other's private from non admin
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
2018-03-22 18:18:28 +00:00
|
|
|
playlist = Playlist.get(lambda p: not p.public and p.user.name == 'alice')
|
2017-11-08 22:21:52 +00:00
|
|
|
self._make_request('getPlaylist', { 'u': 'bob', 'p': 'B0b', 'id': str(playlist.id) }, error = 50)
|
|
|
|
|
|
|
|
# standard
|
|
|
|
rv, child = self._make_request('getPlaylists', tag = 'playlists')
|
2018-03-22 18:18:28 +00:00
|
|
|
self._make_request('getPlaylist', { 'id': child[0].get('id') }, tag = 'playlist')
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': child[1].get('id') }, tag = 'playlist')
|
2017-11-08 22:21:52 +00:00
|
|
|
self.assertEqual(child.get('songCount'), '2')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 2) # don't count children, there may be 'allowedUser's (even though not supported by supysonic)
|
|
|
|
self.assertEqual(child.get('duration'), '4')
|
|
|
|
self.assertEqual(child[0].get('title'), 'One')
|
|
|
|
self.assertTrue(child[1].get('title') == 'Two' or child[1].get('title') == 'Three') # depending on 'getPlaylists' result ordering
|
|
|
|
|
|
|
|
def test_create_playlist(self):
|
|
|
|
self._make_request('createPlaylist', error = 10)
|
|
|
|
self._make_request('createPlaylist', { 'name': 'wrongId', 'songId': 'abc' }, error = 0)
|
|
|
|
self._make_request('createPlaylist', { 'name': 'unknownId', 'songId': str(uuid.uuid4()) }, error = 70)
|
|
|
|
self._make_request('createPlaylist', { 'playlistId': 'abc' }, error = 0)
|
|
|
|
self._make_request('createPlaylist', { 'playlistId': str(uuid.uuid4()) }, error = 70)
|
|
|
|
|
|
|
|
# create
|
|
|
|
self._make_request('createPlaylist', { 'name': 'new playlist' }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylists', tag = 'playlists')
|
|
|
|
self.assertEqual(len(child), 3)
|
|
|
|
playlist = self._find(child, "./playlist[@name='new playlist']")
|
|
|
|
self.assertEqual(len(playlist), 0)
|
|
|
|
|
|
|
|
# "update" newly created
|
|
|
|
self._make_request('createPlaylist', { 'playlistId': playlist.get('id') })
|
|
|
|
rv, child = self._make_request('getPlaylists', tag = 'playlists')
|
|
|
|
self.assertEqual(len(child), 3)
|
|
|
|
|
|
|
|
# renaming
|
|
|
|
self._make_request('createPlaylist', { 'playlistId': playlist.get('id'), 'name': 'renamed' })
|
|
|
|
rv, child = self._make_request('getPlaylists', tag = 'playlists')
|
|
|
|
self.assertEqual(len(child), 3)
|
|
|
|
self.assertIsNone(self._find(child, "./playlist[@name='new playlist']"))
|
|
|
|
playlist = self._find(child, "./playlist[@name='renamed']")
|
|
|
|
self.assertIsNotNone(playlist)
|
|
|
|
|
|
|
|
# update from other user
|
|
|
|
self._make_request('createPlaylist', { 'u': 'bob', 'p': 'B0b', 'playlistId': playlist.get('id') }, error = 50)
|
|
|
|
|
|
|
|
# create more useful playlist
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
songs = { s.title: str(s.id) for s in Track.select() }
|
2018-01-11 22:08:53 +00:00
|
|
|
self._make_request('createPlaylist', { 'name': 'songs', 'songId': list(map(lambda s: songs[s], [ 'Three', 'One', 'Two' ])) }, skip_post = True)
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
playlist = Playlist.get(name = 'songs')
|
2017-11-08 22:21:52 +00:00
|
|
|
self.assertIsNotNone(playlist)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': str(playlist.id) }, tag = 'playlist')
|
|
|
|
self.assertEqual(child.get('songCount'), '3')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 3)
|
|
|
|
self.assertEqual(child[0].get('title'), 'Three')
|
|
|
|
self.assertEqual(child[1].get('title'), 'One')
|
|
|
|
self.assertEqual(child[2].get('title'), 'Two')
|
|
|
|
|
|
|
|
# update
|
|
|
|
self._make_request('createPlaylist', { 'playlistId': str(playlist.id), 'songId': songs['Two'] }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': str(playlist.id) }, tag = 'playlist')
|
|
|
|
self.assertEqual(child.get('songCount'), '1')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 1)
|
|
|
|
self.assertEqual(child[0].get('title'), 'Two')
|
|
|
|
|
2017-12-23 21:59:04 +00:00
|
|
|
@db_session
|
|
|
|
def assertPlaylistCountEqual(self, count):
|
|
|
|
self.assertEqual(Playlist.select().count(), count)
|
|
|
|
|
2017-11-08 22:21:52 +00:00
|
|
|
def test_delete_playlist(self):
|
|
|
|
# check params
|
|
|
|
self._make_request('deletePlaylist', error = 10)
|
|
|
|
self._make_request('deletePlaylist', { 'id': 'string' }, error = 0)
|
|
|
|
self._make_request('deletePlaylist', { 'id': str(uuid.uuid4()) }, error = 70)
|
|
|
|
|
|
|
|
# delete unowned when not admin
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
playlist = Playlist.select(lambda p: p.user.name == 'alice').first()
|
2017-11-08 22:21:52 +00:00
|
|
|
self._make_request('deletePlaylist', { 'u': 'bob', 'p': 'B0b', 'id': str(playlist.id) }, error = 50)
|
2017-12-23 21:59:04 +00:00
|
|
|
self.assertPlaylistCountEqual(3);
|
2017-11-08 22:21:52 +00:00
|
|
|
|
|
|
|
# delete owned
|
|
|
|
self._make_request('deletePlaylist', { 'id': str(playlist.id) }, skip_post = True)
|
2017-12-23 21:59:04 +00:00
|
|
|
self.assertPlaylistCountEqual(2);
|
2017-11-08 22:21:52 +00:00
|
|
|
self._make_request('deletePlaylist', { 'id': str(playlist.id) }, error = 70)
|
2017-12-23 21:59:04 +00:00
|
|
|
self.assertPlaylistCountEqual(2);
|
2017-11-08 22:21:52 +00:00
|
|
|
|
|
|
|
# delete unowned when admin
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
playlist = Playlist.get(lambda p: p.user.name == 'bob')
|
2017-11-08 22:21:52 +00:00
|
|
|
self._make_request('deletePlaylist', { 'id': str(playlist.id) }, skip_post = True)
|
2017-12-23 21:59:04 +00:00
|
|
|
self.assertPlaylistCountEqual(1);
|
2017-11-08 22:21:52 +00:00
|
|
|
|
|
|
|
def test_update_playlist(self):
|
|
|
|
self._make_request('updatePlaylist', error = 10)
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': 1234 }, error = 0)
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': str(uuid.uuid4()) }, error = 70)
|
|
|
|
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
playlist = Playlist.select(lambda p: p.user.name == 'alice').order_by(Playlist.created).first()
|
2017-11-08 22:21:52 +00:00
|
|
|
pid = str(playlist.id)
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIdToAdd': 'string' }, error = 0)
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIndexToRemove': 'string' }, error = 0)
|
|
|
|
|
|
|
|
name = str(playlist.name)
|
|
|
|
self._make_request('updatePlaylist', { 'u': 'bob', 'p': 'B0b', 'playlistId': pid, 'name': 'new name' }, error = 50)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertEqual(child.get('name'), name)
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 2)
|
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'name': 'new name' }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertEqual(child.get('name'), 'new name')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 2)
|
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIndexToRemove': [ -1, 2 ] }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 2)
|
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIndexToRemove': [ 0, 2 ] }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 1)
|
|
|
|
self.assertEqual(self._find(child, './entry').get('title'), 'Three')
|
|
|
|
|
2017-12-23 21:59:04 +00:00
|
|
|
with db_session:
|
|
|
|
songs = { s.title: str(s.id) for s in Track.select() }
|
2017-11-08 22:21:52 +00:00
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIdToAdd': [ songs['One'], songs['Two'], songs['Two'] ] }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertSequenceEqual(self._xpath(child, './entry/@title'), [ 'Three', 'One', 'Two', 'Two' ])
|
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIndexToRemove': [ 2, 1 ] }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertSequenceEqual(self._xpath(child, './entry/@title'), [ 'Three', 'Two' ])
|
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIdToAdd': songs['One'] }, skip_post = True)
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIndexToRemove': [ 1, 1 ] }, skip_post = True)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertSequenceEqual(self._xpath(child, './entry/@title'), [ 'Three', 'One' ])
|
|
|
|
|
|
|
|
self._make_request('updatePlaylist', { 'playlistId': pid, 'songIdToAdd': str(uuid.uuid4()) }, error = 70)
|
|
|
|
rv, child = self._make_request('getPlaylist', { 'id': pid }, tag = 'playlist')
|
|
|
|
self.assertEqual(self._xpath(child, 'count(./entry)'), 2)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main()
|
|
|
|
|