1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00
supysonic/tests/base/test_db.py
2024-09-08 15:02:01 -04:00

328 lines
11 KiB
Python

# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2017-2023 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.
import re
import unittest
import uuid
from collections import namedtuple
from peewee import IntegrityError
from supysonic import db
date_regex = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$")
class DbTestCase(unittest.TestCase):
def setUp(self):
db.init_database("sqlite:")
def tearDown(self):
db.release_database()
def create_some_folders(self):
root_folder = db.Folder.create(root=True, name="Root folder", path="tests")
f1 = db.Folder.create(
root=False,
name="Child folder",
path="tests/assets",
cover_art="cover.jpg",
parent=root_folder,
)
f2 = db.Folder.create(
root=False,
name="Child folder (No Art)",
path="tests/formats",
parent=root_folder,
)
return root_folder, f1, f2
def create_some_tracks(self, artist=None, album=None):
root, child, child_2 = self.create_some_folders()
if not artist:
artist = db.Artist.create(name="Test artist")
if not album:
album = db.Album.create(artist=artist, name="Test Album")
track1 = db.Track.create(
title="Track Title",
album=album,
artist=artist,
disc=1,
number=1,
duration=3599,
has_art=True,
bitrate=320,
path="tests/assets/formats/silence.ogg",
last_modification=1234,
root_folder=root,
folder=child,
)
track2 = db.Track.create(
title="One Awesome Song",
album=album,
artist=artist,
disc=1,
number=2,
duration=3600,
bitrate=96,
path="tests/assets/23bytes",
last_modification=1234,
root_folder=root,
folder=child,
)
return track1, track2
def create_track_in(self, folder, root, artist=None, album=None, has_art=True):
artist = artist or db.Artist.create(name="Snazzy Artist")
album = album or db.Album.create(artist=artist, name="Rockin' Album")
return db.Track.create(
title="Nifty Number",
album=album,
artist=artist,
disc=1,
number=1,
duration=5,
has_art=has_art,
bitrate=96,
path="tests/assets/formats/silence.flac",
last_modification=1234,
root_folder=root,
folder=folder,
)
def create_user(self, name="Test User"):
return db.User.create(name=name, password="secret", salt="ABC+")
def create_playlist(self):
playlist = db.Playlist.create(user=self.create_user(), name="Playlist!")
return playlist
def test_ensure_sqlite_foreign_keys(self):
root, _, _ = self.create_some_folders()
self.assertRaises(IntegrityError, root.delete_instance)
def test_folder_base(self):
root_folder, child_folder, child_noart = self.create_some_folders()
track_embededart = self.create_track_in(child_noart, root_folder)
MockUser = namedtuple("User", ["id"])
user = MockUser(uuid.uuid4())
root = root_folder.as_subsonic_child(user)
self.assertIsInstance(root, dict)
self.assertIn("id", root)
self.assertIn("isDir", root)
self.assertIn("title", root)
self.assertIn("album", root)
self.assertIn("created", root)
self.assertTrue(root["isDir"])
self.assertEqual(root["title"], "Root folder")
self.assertEqual(root["album"], "Root folder")
self.assertRegex(root["created"], date_regex)
child = child_folder.as_subsonic_child(user)
self.assertIn("parent", child)
self.assertIn("artist", child)
self.assertIn("coverArt", child)
self.assertEqual(child["parent"], str(root_folder.id))
self.assertEqual(child["artist"], root_folder.name)
self.assertEqual(child["coverArt"], child["id"])
noart = child_noart.as_subsonic_child(user)
self.assertIn("coverArt", noart)
self.assertEqual(noart["coverArt"], str(track_embededart.id))
def test_folder_annotation(self):
root_folder, child_folder, _ = self.create_some_folders()
user = self.create_user()
db.StarredFolder.create(user=user, starred=root_folder)
db.RatingFolder.create(user=user, rated=root_folder, rating=2)
other = self.create_user("Other")
db.RatingFolder.create(user=other, rated=root_folder, rating=5)
root = root_folder.as_subsonic_child(user)
self.assertIn("starred", root)
self.assertIn("userRating", root)
self.assertIn("averageRating", root)
self.assertRegex(root["starred"], date_regex)
self.assertEqual(root["userRating"], 2)
self.assertEqual(root["averageRating"], 3.5)
child = child_folder.as_subsonic_child(user)
self.assertNotIn("starred", child)
self.assertNotIn("userRating", child)
def test_artist(self):
artist = db.Artist.create(name="Test Artist")
user = self.create_user()
db.StarredArtist.create(user=user, starred=artist)
artist_dict = artist.as_subsonic_artist(user)
self.assertIsInstance(artist_dict, dict)
self.assertIn("id", artist_dict)
self.assertIn("name", artist_dict)
self.assertIn("albumCount", artist_dict)
self.assertIn("starred", artist_dict)
self.assertEqual(artist_dict["name"], "Test Artist")
self.assertEqual(artist_dict["albumCount"], 0)
self.assertRegex(artist_dict["starred"], date_regex)
db.Album.create(name="Test Artist", artist=artist) # self-titled
db.Album.create(name="The Album After The First One", artist=artist)
artist_dict = artist.as_subsonic_artist(user)
self.assertEqual(artist_dict["albumCount"], 2)
def test_album(self):
artist = db.Artist.create(name="Test Artist")
album = db.Album.create(artist=artist, name="Test Album")
user = self.create_user()
db.StarredAlbum.create(user=user, starred=album)
root_folder, folder_art, folder_noart = self.create_some_folders()
track1 = self.create_track_in(
folder_noart, root_folder, artist=artist, album=album
)
album_dict = album.as_subsonic_album(user)
self.assertIsInstance(album_dict, dict)
self.assertIn("id", album_dict)
self.assertIn("name", album_dict)
self.assertIn("artist", album_dict)
self.assertIn("artistId", album_dict)
self.assertIn("songCount", album_dict)
self.assertIn("duration", album_dict)
self.assertIn("created", album_dict)
self.assertIn("starred", album_dict)
self.assertIn("coverArt", album_dict)
self.assertEqual(album_dict["name"], album.name)
self.assertEqual(album_dict["artist"], artist.name)
self.assertEqual(album_dict["artistId"], str(artist.id))
self.assertEqual(album_dict["songCount"], 1)
self.assertEqual(album_dict["duration"], 5)
self.assertEqual(album_dict["coverArt"], str(track1.id))
self.assertRegex(album_dict["created"], date_regex)
self.assertRegex(album_dict["starred"], date_regex)
def test_track(self):
track1, track2 = self.create_some_tracks()
assert track1.duration_str() == "59:59"
assert track2.duration_str() == "01:00:00"
# Assuming SQLite doesn't enforce foreign key constraints
MockUser = namedtuple("User", ["id"])
user = MockUser(uuid.uuid4())
track1_dict = track1.as_subsonic_child(user, None)
self.assertIsInstance(track1_dict, dict)
self.assertIn("id", track1_dict)
self.assertIn("parent", track1_dict)
self.assertIn("isDir", track1_dict)
self.assertIn("title", track1_dict)
self.assertFalse(track1_dict["isDir"])
self.assertIn("coverArt", track1_dict)
self.assertEqual(track1_dict["coverArt"], track1_dict["id"])
track2_dict = track2.as_subsonic_child(user, None)
self.assertEqual(track2_dict["coverArt"], track2_dict["parent"])
# ... we'll test the rest against the API XSD.
def test_user(self):
user = self.create_user()
user_dict = user.as_subsonic_user()
self.assertIsInstance(user_dict, dict)
def test_chat(self):
user = self.create_user()
line = db.ChatMessage(user=user, message="Hello world!")
line_dict = line.responsize()
self.assertIsInstance(line_dict, dict)
self.assertIn("username", line_dict)
self.assertEqual(line_dict["username"], user.name)
def test_playlist(self):
playlist = self.create_playlist()
playlist_dict = playlist.as_subsonic_playlist(playlist.user)
self.assertIsInstance(playlist_dict, dict)
def test_playlist_tracks(self):
playlist = self.create_playlist()
track1, track2 = self.create_some_tracks()
playlist.add(track1)
playlist.add(track2)
self.assertSequenceEqual(playlist.get_tracks(), [track1, track2])
playlist.add(track2.id)
playlist.add(track1.id)
self.assertSequenceEqual(
playlist.get_tracks(), [track1, track2, track2, track1]
)
playlist.clear()
self.assertSequenceEqual(playlist.get_tracks(), [])
playlist.add(str(track1.id))
self.assertSequenceEqual(playlist.get_tracks(), [track1])
self.assertRaises(ValueError, playlist.add, "some string")
self.assertRaises(NameError, playlist.add, 2345)
def test_playlist_remove_tracks(self):
playlist = self.create_playlist()
track1, track2 = self.create_some_tracks()
playlist.add(track1)
playlist.add(track2)
playlist.remove_at_indexes([0, 2])
self.assertSequenceEqual(playlist.get_tracks(), [track2])
playlist.add(track1)
playlist.add(track2)
playlist.add(track2)
playlist.remove_at_indexes([2, 1])
self.assertSequenceEqual(playlist.get_tracks(), [track2, track2])
playlist.add(track1)
playlist.remove_at_indexes([1, 1])
self.assertSequenceEqual(playlist.get_tracks(), [track2, track1])
def test_playlist_fixing(self):
playlist = self.create_playlist()
track1, track2 = self.create_some_tracks()
playlist.add(track1)
playlist.add(uuid.uuid4())
playlist.add(track2)
self.assertSequenceEqual(playlist.get_tracks(), [track1, track2])
track2.delete_instance()
self.assertSequenceEqual(playlist.get_tracks(), [track1])
playlist.tracks = "{0},{0},some random garbage,{0}".format(track1.id)
self.assertSequenceEqual(playlist.get_tracks(), [track1, track1, track1])
if __name__ == "__main__":
unittest.main()